MicroHTR (Part 5)
Part 1, 2, 3, 4, 5, 6, 7, 8, 9
Few more lines of code are required to build a fully operational PID. In the case of a PWM control, we need to get an output value ranging from 0 to 100% (Duty cycle). But other applications may require different ranges. That is the reason why we shall set extra global parameters and use them in the following way:
/* Compute output */ double outputValue = (_Kp * error) + (_Ki * _integralError) + (_Kd * dError); outputValue *= (_limitUpp - _limitLow); outputValue += _limitLow; /* Constrain output signal to predefined values */ if (outputValue < _limitLow) { outputValue = _limitLow; } else if (outputValue > _limitUpp) { outputValue = _limitUpp; }
In this way, the PID function output shall be constrained within the _limitLow and _limitUpp bounds. Finally with get a fully operating PID which will work fine for controlling heating systems.
double PlainPID::PIDOutput(double processVariable) /* Compute output signal */ { _actualPointValue = processVariable; /* Timing stuff */ uint32_t now = millis(); double timeInterval = (now - _lastTime) / 1000.0; /* Auto adjust set point in order to prevent windup and spikes */ if (_firstPass == 0x01) { _computedSetpoint = processVariable; _firstPass = 0x00; } if (_computedSetpoint != _setpoint) { /* Reset integral of errors */ _integralError = 0; if (_computedSetpoint < _setpoint) { _computedSetpoint = (processVariable + 1); if (_computedSetpoint > _setpoint) { _computedSetpoint = _setpoint; } } else if (_computedSetpoint > _setpoint) { _computedSetpoint = (processVariable - 1); if (_computedSetpoint < _setpoint) { _computedSetpoint = _setpoint; } } } /* Compute error */ double error = (_computedSetpoint - processVariable); /* Compute error derivative */ double dError = (error - _lastError) / timeInterval; /* Compute error integral */ _integralError += ((error + _lastError ) * timeInterval) / 2.0; /* Compute output */ double outputValue = (_Kp * error) + (_Ki * _integralError) + (_Kd * dError); outputValue *= (_limitUpp - _limitLow); outputValue += _limitLow; /* Constrain output signal to predefined values */ if (outputValue < _limitLow) { outputValue = _limitLow; } else if (outputValue > _limitUpp) { outputValue = _limitUpp; } /* Save last values in volatile variables */ _lastTime = now; _lastError = error; return(outputValue); };