yarf 0.1
Yet Another RepRap Firmware
|
00001 /* 00002 * pid.c 00003 * 00004 * Copyright 2011 Pieter Agten 00005 * 00006 * This file is part of Yarf. 00007 * 00008 * Yarf is free software: you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation, either version 3 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * Yarf is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with Yarf. If not, see <http://www.gnu.org/licenses/>. 00020 * 00021 */ 00022 00034 #include "pid.h" 00035 #include "yarf.h" 00036 00037 #include "util/math.h" 00038 00039 #include <stdint.h> 00040 00046 static inline void 00047 reset_state(pid_t *pid) { 00048 pid->i_state = 0; 00049 } 00050 00051 void 00052 pid_init(pid_t *pid, uint8_t envelope, uint8_t p, uint8_t i, uint8_t d) 00053 { 00054 pid->envelope = envelope; 00055 pid->p_gain = p; 00056 pid->i_gain = i; 00057 pid->d_gain = d; 00058 pid->i_state = 0; 00059 pid->d_term = 0; 00060 pid->target_temp = 0; 00061 pid->last_temp = 0; 00062 } 00063 00064 00065 void 00066 pid_set_target(pid_t *pid, float target_temp) 00067 { 00068 pid->target_temp = target_temp; 00069 } 00070 00071 00072 00073 uint8_t 00074 pid_next(pid_t *pid, float current_temp) 00075 { 00076 float error = pid->target_temp - current_temp; 00077 if (error > pid->envelope) { 00078 reset_state(pid); 00079 return 255; 00080 } else if (error < -pid->envelope) { 00081 reset_state(pid); 00082 return 0; 00083 } else { 00084 float result = 0; 00085 00086 // Proportional: 00087 result = error * pid->p_gain; 00088 00089 // Integral: 00090 pid->i_state += error; 00091 result += pid->i_state * pid->i_gain; 00092 00093 // Derivative 00094 pid->d_term = ((pid->last_temp - current_temp)*0.2 + pid->d_term * 0.8) * pid->d_gain; 00095 pid->last_temp = current_temp; 00096 result += pid->d_term; 00097 00098 return (uint8_t)MIN(MAX(lround(result),0),255); 00099 } 00100 } 00101