For revision 3 of my grill controller, I made it start with a Ziegler–Nichols [auto tuning] state before moving to a [hold] state—the idea being to learn the characteristics of the grill/smoker it was attached to. I graphed the log data from multiple tests to find optimal PID parameters for my smoker, and found that there were no consistently optimal PID parameters.
This makes sense. At the start of a cook, more air is needed to catch fuel and get to setpoint. When fuel has caught, less air is needed to hold temp. When the fuel is almost out, more air is needed again. When the fuel is out, bringing in air is the opposite thing needed to (try and) maintain temperature.
This presents a problem because PID relies on a relatively consistent relationship between input and output. So I treated it like a tuning problem. I added logic to track peaks, valleys, and when the process variable crossed the setpoint/in which direction. I set it to tune the coefficients and stored-up integration accordingly, to reduce the amplitude of errors, increase responsiveness when needed, and minimize oscillation. In short, Always Be Tuning.