博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【龙印】以程序员的角度整定3d打印机的pid实现控温
阅读量:2359 次
发布时间:2019-05-10

本文共 18563 字,大约阅读时间需要 61 分钟。

本文为在用龙芯1c做3D打印机过程中的笔记。龙芯1c做的3d打印机简称“龙印”,Git地址“https://gitee.com/caogos/marlin_ls1c”

网上pid的资料很多,但展示整定全过程的视频不多。这里以龙芯1c的智龙开源主板+ramps1.4扩展板实现的3D打印机用pid控温为例,以程序员的角度整定pid,在大致确定温度采样周期和控制加热装置的pwm周期后,主要通过调节比例项、积分项、微分项和维持功率项的系数来将温度控制在指定范围。

温度采样周期的选择:以在温度快速变化时,相邻两次或三次采集的温度有变化,变化又不至于太大为宜。这句话怎么理解,首先温度变化从微观上讲并不是曲线,而是梯形,这个不会随温度采样周期的大小而改变。如果采用周期太小,则会看到连续采样几次的值都是一样的,采样周期太大,则会发现相邻两次的温度变化太大,这个根据实际情况选择一个合适的值。比如,我把温度采集周期设置为500ms,即每秒采集两次。

加热装置的pwm周期的选择:加热装置的pwm周期最好不要大于温度采集周期,否则温度采集后,计算得到的pid值,不能很好的传递给加热装置执行。即加热装置还未执行完上一次pid计算得到的结果,又有一个新的pid值需要执行。个人认为加热装置的pwm周期小于或等于温度采集周期的一半比较合适。比如,我把加热头的pwm周期设为200ms。

温度采集周期一旦确定,那么pid的微分时间就确定了。

pid的积分时间通常由代码确定,即当前温度与目标温度相差n度时才开始积分,当温度超过这个限定后将积分项清零,待又回到区间内时重新积分。还可以为积分作用加些保护措施。

所以本文主要调节pid系数,而非积分时间,微分时间。但是以正确温度采集周期和加热装置的pwm周期为前提,一旦温度采集周期或加热装置的pwm周期改变了,应该重新检查之前的pid系数是否还合适。

硬件

cpu:龙芯1c

主板:智龙

扩展板:开源3d打印机扩展板ramps1.4(主要用了其中的STP55NF06L控制加热头)

温度采集:热敏电阻+AD芯片TM7705

源码

在linux上实现的。其中的文章之前已经写了,控制加热头的pwm也是linux驱动中的软件定时器模拟的,这里重点关注pid算法和整定过程。完整的代码在http://git.oschina.net/caogos/marlin_ls1c

加热头和风扇驱动

/* * include\linux\ls1c_3dprinter_heater_fan.h * 3d打印机加热头和风扇(散热)驱动的头文件 */#ifndef MY_LS1C_3DPRINTER_HEATER_FAN_H#define MY_LS1C_3DPRINTER_HEATER_FAN_H// 挤出机加热头的gpio#define PRINTER_EXTRUDER_HEATER_PIN     (90)    // I2S_BCLK/GPIO90// 挤出机散热风扇的gpio#define PRINTER_EXTRUDER_FAN_PIN        (91)    // I2S_MCLK/GPIO91struct platform_3dprinter_heater_fan_data {    unsigned char extruder_heater_gpio;         // 挤出机加热头的gpio    unsigned char extruder_fan_gpio;            // 挤出机散热风扇的gpio};#endif
/* * drivers\misc\ls1c_3dprinter_heater_fan.c * 3d打印机加热头和风扇(散热)驱动 * 用linux内核定时器模拟pwm */ #include 
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
// pwm周期(ms)#define HEATER_FAN_PWM_TIME_MS (200) // 200msenum{ HEATER_NOT_WORK = 0, // 不加热(加热装置不工作) HEATER_WORK = 1, // 加热(加热装置正常工作)};enum{ FAN_NOT_WORK = 0, // 不散热(风扇不工作) FAN_WORK = 1, // 散热(风扇正常工作)};// 一个pwm周期内,工作的时长,单位ms// 由于驱动中不能进行浮点计算// 所以在应用程序中将pid的占空比直接换算为一个周期内加热头和散热的风扇工作的时长typedef struct{ unsigned int extruder_heater_ms; // 挤出机加热的时长(ms) unsigned int extruder_fan_ms; // 挤出机风扇工作的时长(ms)}heater_fan_work_time_t;static heater_fan_work_time_t heater_fan_work_time = {0};static struct platform_3dprinter_heater_fan_data *heater_fan_data = NULL;// 用于模拟pwm的定时器static struct timer_list extruder_heater_timer; // 挤出机加热的定时器static struct timer_list extruder_fan_timer; // 挤出机散热风扇的定时器static DEFINE_MUTEX(heater_fan_lock);// 给挤出机加热static void extruder_heater_enable(void){ gpio_direction_output(heater_fan_data->extruder_heater_gpio, HEATER_WORK);}// 挤出机不加热static void extruder_heater_disable(void){ gpio_direction_output(heater_fan_data->extruder_heater_gpio, HEATER_NOT_WORK);}// 给挤出机散热static void extruder_fan_enable(void){ gpio_direction_output(heater_fan_data->extruder_fan_gpio, FAN_WORK);}// 不给挤出机散热static void extruder_fan_disable(void){ gpio_direction_output(heater_fan_data->extruder_fan_gpio, FAN_NOT_WORK);}// 挤出机加热定时器中断(模拟pwm)void extruder_heater_timer_timeout_fn(unsigned long arg){ static int level = 0; // 判断是否需要加热 if (0 == heater_fan_work_time.extruder_heater_ms) { // 不需要加热 extruder_heater_disable(); mod_timer(&extruder_heater_timer, jiffies + HEATER_FAN_PWM_TIME_MS); level = 0; return ; } // 是否在整个pwm周期内一直加热 if (HEATER_FAN_PWM_TIME_MS <= heater_fan_work_time.extruder_heater_ms) { // 一直加热 extruder_heater_enable(); mod_timer(&extruder_heater_timer, jiffies + HEATER_FAN_PWM_TIME_MS); level = 0; return ; } // 模拟pwm if (0 == level) { level = 1; extruder_heater_enable(); mod_timer(&extruder_heater_timer, jiffies + heater_fan_work_time.extruder_heater_ms); } else { level = 0; extruder_heater_disable(); mod_timer(&extruder_heater_timer, jiffies + (HEATER_FAN_PWM_TIME_MS - heater_fan_work_time.extruder_heater_ms)); } return ;}// 挤出机散热风扇定时器中断(模拟pwm)void extruder_fan_timer_timeout_fn(unsigned long arg){ static int level = 0; // 判断是否需要散热 if (0 == heater_fan_work_time.extruder_fan_ms) { // 不需要散热 extruder_fan_disable(); mod_timer(&extruder_fan_timer, jiffies + HEATER_FAN_PWM_TIME_MS); level = 0; return ; } // 判断是否在整个pwm周期内一直散热 if (HEATER_FAN_PWM_TIME_MS <= heater_fan_work_time.extruder_fan_ms) { // 一直散热 extruder_fan_enable(); mod_timer(&extruder_fan_timer, jiffies + HEATER_FAN_PWM_TIME_MS); level = 0; return ; } // 模拟pwm if (0 == level) { level = 1; extruder_fan_enable(); mod_timer(&extruder_fan_timer, jiffies + heater_fan_work_time.extruder_fan_ms); } else { level = 0; extruder_fan_disable(); mod_timer(&extruder_fan_timer, jiffies + (HEATER_FAN_PWM_TIME_MS - heater_fan_work_time.extruder_fan_ms)); } return ;}static int heater_fan_open(struct inode *inode, struct file *filep){ int hz = HZ; printk(KERN_DEBUG "[%s] HZ=%d, 1000 is expected.\n", __FUNCTION__, hz); return 0;}static int heater_fan_close(struct inode *inode, struct file *filep){ // 停止挤出机的加热和风扇 extruder_heater_disable(); extruder_fan_disable(); heater_fan_work_time.extruder_heater_ms = 0; heater_fan_work_time.extruder_fan_ms = 0; return 0;}static ssize_t heater_fan_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp){ heater_fan_work_time_t work_time = {0}; if (sizeof(heater_fan_work_time_t) != count) { // 写入额数据不对 return 0; } if (mutex_lock_interruptible(&heater_fan_lock)) { return -ERESTARTSYS; } copy_from_user(&work_time, buf, sizeof(heater_fan_work_time_t)); heater_fan_work_time.extruder_heater_ms = work_time.extruder_heater_ms; heater_fan_work_time.extruder_fan_ms = work_time.extruder_fan_ms; mutex_unlock(&heater_fan_lock); return 0;}static struct file_operations ls1c_heater_fan_ops = { .owner = THIS_MODULE, .open = heater_fan_open, .release = heater_fan_close, .write = heater_fan_write,};static struct miscdevice ls1c_heater_fan_miscdev = { .minor = MISC_DYNAMIC_MINOR, .name = "3dPrinter_heater_fan", .fops = &ls1c_heater_fan_ops,};static int heater_fan_probe(struct platform_device *pdev){ int ret = 0; printk(KERN_INFO "ls1c 3dprinter heater fan driver's build time %s %s\n", __DATE__, __TIME__); heater_fan_data = pdev->dev.platform_data; if (!heater_fan_data) { dev_err(&pdev->dev, "failed to find platform data\n"); return -EINVAL; } // 挤出机加热头 ret = gpio_request(heater_fan_data->extruder_heater_gpio, "ls1c_3dPrinter_heater_fan"); if (0 > ret) { printk(KERN_ERR "[%s] request extruder heater gpio fail.", __FUNCTION__); return ret; } gpio_direction_output(heater_fan_data->extruder_heater_gpio, HEATER_NOT_WORK); // 挤出机散热风扇 ret = gpio_request(heater_fan_data->extruder_fan_gpio, "ls1c_3dPrinter_heater_fan"); if (0 > ret) { printk(KERN_ERR "[%s] request extruder fan gpio fail.\n", __FUNCTION__); goto fail_request_fan; } gpio_direction_output(heater_fan_data->extruder_fan_gpio, FAN_NOT_WORK); // 初始化挤出机加热的定时器(用于模拟pwm) heater_fan_work_time.extruder_heater_ms = 0; // 加热头不工作 init_timer(&extruder_heater_timer); extruder_heater_timer.function = extruder_heater_timer_timeout_fn; extruder_heater_timer.expires = jiffies + HEATER_FAN_PWM_TIME_MS; add_timer(&extruder_heater_timer); // 初始化挤出机散热风扇的定时器(用于模拟pwm) heater_fan_work_time.extruder_fan_ms = 0; // 风扇不工作 init_timer(&extruder_fan_timer); extruder_fan_timer.function = extruder_fan_timer_timeout_fn; extruder_fan_timer.expires = jiffies + HEATER_FAN_PWM_TIME_MS; add_timer(&extruder_fan_timer); return 0;fail_request_fan: gpio_free(heater_fan_data->extruder_heater_gpio); return ret;}static int heater_fan_remove(struct platform_device *pdev){ gpio_free(heater_fan_data->extruder_heater_gpio); gpio_free(heater_fan_data->extruder_fan_gpio); del_timer(&extruder_heater_timer); del_timer(&extruder_fan_timer); return 0;}static struct platform_driver ls1c_heater_fan_driver = { .driver = { .name = "ls1c_3dPrinter_heater_fan", .owner = THIS_MODULE, }, .probe = heater_fan_probe, .remove = heater_fan_remove,};static int __init heater_fan_init(void){ if (misc_register(&ls1c_heater_fan_miscdev)) { printk(KERN_ERR "could not register 3dPrinter heater fan driver!\n"); return -EBUSY; } return platform_driver_register(&ls1c_heater_fan_driver);}static void __exit heater_fan_exit(void){ misc_deregister(&ls1c_heater_fan_miscdev); platform_driver_unregister(&ls1c_heater_fan_driver);}module_init(heater_fan_init);module_exit(heater_fan_exit);MODULE_AUTHOR("勤为本");MODULE_DESCRIPTION("ls1c 3dprinter heater and fan driver");MODULE_LICENSE("GPL");文件“ls1c_3dprinter_heater_fan.h”放到linux源码目录\include\linux下文件“ls1c_3dprinter_heater_fan.c”放到linux源码目录\drivers\misc下在“linux源码目录\arch\mips\loongson\ls1x\ls1cplatform.c”中,增加#ifdef CONFIG_LS1C_3DPRINTER_HEATER_FAN#include
static struct platform_3dprinter_heater_fan_data ls1c_3dPrinter_heater_fan_data = {    .extruder_heater_gpio       = PRINTER_EXTRUDER_HEATER_PIN,    .extruder_fan_gpio          = PRINTER_EXTRUDER_FAN_PIN,};static struct platform_device ls1c_3dPrinter_heater_fan = {    .name   = "ls1c_3dPrinter_heater_fan",    .dev    = {        .platform_data = &ls1c_3dPrinter_heater_fan_data,    },};#endif在“static struct platform_device *ls1b_platform_devices[] __initdata”中,添加#ifdef CONFIG_LS1C_3DPRINTER_HEATER_FAN    &ls1c_3dPrinter_heater_fan,#endif在“linux源码目录\drivers\misc\Kconfig”中,添加config LS1C_3DPRINTER_HEATER_FAN    tristate "ls1c 3dprinter heater and fan"    depends on LS1C_MACH    help     Say Y here if you want to build a 3dprinter heater and fan driver for ls1c     在“linux源码目录\drivers\misc\Makefile”中,添加obj-$(CONFIG_LS1C_3DPRINTER_HEATER_FAN) += ls1c_3dprinter_heater_fan.omake menuconfig  Kernel type  --->    [*] High Resolution Timer Support        Timer frequency (1000 HZ)  --->  Device Drivers  --->    [*] Misc devices  --->      <*>   ls1c 3dprinter heater and fan       

应用程序(包括pid算法)

configuration.h

// 配置头文件#ifndef __CONFIGURATION_H#define __CONFIGURATION_H// Make delta curves from many straight lines (linear interpolation).// This is a trade-off between visible corners (not enough segments)// and processor overload (too many expensive sqrt calls).#define DELTA_SEGMENTS_PER_SECOND 200// NOTE NB all values for DELTA_* values MUST be floating point, so always have a decimal point in them// Center-to-center distance of the holes in the diagonal push rods.// 杆长#define DELTA_DIAGONAL_ROD 220.0 // mm// Horizontal offset from middle of printer to smooth rod center.// 电机轴的圆半径(电机轴组成的等边三角形的最小外接圆的半径)#define DELTA_SMOOTH_ROD_OFFSET 152.0 // mm// Horizontal offset of the universal joints on the end effector.// 装喷嘴的平台的中心到杆连接处的距离#define DELTA_EFFECTOR_OFFSET 35.0 // mm// Horizontal offset of the universal joints on the carriages.//电机轴滑块的距离#define DELTA_CARRIAGE_OFFSET 25.0 // mm// Horizontal distance bridged by diagonal push rods when effector is centered.#define DELTA_RADIUS (DELTA_SMOOTH_ROD_OFFSET-DELTA_EFFECTOR_OFFSET-DELTA_CARRIAGE_OFFSET)// Print surface diameter/2 minus unreachable space (avoid collisions with vertical towers).#define DELTA_PRINTABLE_RADIUS 70// Travel limits after homing (units are in mm)#define X_MIN_POS -DELTA_PRINTABLE_RADIUS#define Y_MIN_POS -DELTA_PRINTABLE_RADIUS#define Z_MIN_POS 0#define X_MAX_POS DELTA_PRINTABLE_RADIUS#define Y_MAX_POS DELTA_PRINTABLE_RADIUS#define Z_MAX_POS 343// 步进电机跑一圈的步数 / 一圈运行的距离// 42步进电机一圈200步,16细分,所以一圈步数=16*200=3200// 步进电机跑一圈运行的距离就需要测了#define DEFAULT_AXIS_STEPS_PER_UNIT         {100.0, 100.0, 100.0, 100.0}// pid的取值范围[0,1]#define PID_MAX                             (1)#define PID_MIN                             (0)// 虽然理论上,pid值在区间[PID_MIN, PID_MAX]之间都可以// 但pid值太小,开关器件不会动作,等同于为0// 所以当pid值小于此阀值时,直接取0#define PID_ACTION_MIN                      (0.02)// 加热装置惯性太大,在长时间加热是使用较小的pid值#define PID_LONG_TIME_ACTION                (0.4)// pid的调节范围// 当前温度与目标温度的偏差大于该值时,将把pid值设为最大或最小(即全速加热或者不加热)#define PID_FUNCTIONAL_RANGE                (5)// 当温度偏差在区间[-PID_FUNCTIONAL_RANGE, PID_FUNCTIONAL_RANGE]内 // 即当前温度在目标温度附近才使用pid算法控温// pid的系数#define DEFUALT_Kp                          (0.15)#define DEFAULT_Ki                          (0.0015)#define DEFAULT_Kd                          (1)#define DEFAULT_Kc                          (0.0008)// 平滑因子#define PID_SMOOTHING_FACTOR                (0.5)#endif

temp.c

// 温度相关#include 
#include
#include
#include
#include
#include
#include
#include "public.h"#include "configuration.h"#define TEMP_AD_MAX ((0x1<<10)-1) // ad的最大值,ad是十位的#define TEMP_IS_VALID_AD(ad) ((TEMP_AD_MAX>=(ad)) && (0<=(ad))) // 判断ad是在量程范围内#define TEMP_BUFF_SIZE (64) // 缓存大小// 加热头和散热风扇的pwm周期(ms)#define HEATER_FAN_PWM_TIME_MS (200) // 200ms// TM7705的通道enum{ TM7705_CH_1 = 0, // 通道1 TM7705_CH_2 = 1 // 通道2};// 以下根据ntc热敏电阻参数用脚本生成的adc值与温度一一对应的表格// 左边为adc值,右边为温度(单位:摄氏度)// 详细请参考源码目录中的脚本"createTemperatureLookup.py"// python createTemperatureLookup.py// Thermistor lookup table for RepRap Temperature Sensor Boards (http://make.rrrf.org/ts)// Made with createTemperatureLookup.py (http://svn.reprap.org/trunk/reprap/firmware/Arduino/utilities/createTemperatureLookup.py)// ./createTemperatureLookup.py --r0=100000 --t0=25 --r1=0 --r2=4700 --beta=3950 --max-adc=1023// r0: 100000// t0: 25// r1: 0// r2: 4700// beta: 3950// max adc: 1023#define NUMTEMPS 40const short temptable[NUMTEMPS][2] = { {1, 938}, {27, 326}, {53, 269}, {79, 239}, {105, 219}, {131, 204}, {157, 192}, {183, 182}, {209, 174}, {235, 166}, {261, 160}, {287, 153}, {313, 148}, {339, 143}, {365, 138}, {391, 133}, {417, 129}, {443, 125}, {469, 120}, {495, 116}, {521, 113}, {547, 109}, {573, 105}, {599, 101}, {625, 98}, {651, 94}, {677, 90}, {703, 86}, {729, 82}, {755, 78}, {781, 74}, {807, 70}, {833, 65}, {859, 60}, {885, 54}, {911, 48}, {937, 41}, {963, 31}, {989, 18}, {1015, -8}};// 一个pwm周期内,工作的时长,单位ms// 由于驱动中不能进行浮点计算// 所以在应用程序中将pid的占空比直接换算为一个周期内加热头和散热的风扇工作的时长typedef struct{ unsigned int extruder_heater_ms; // 挤出机加热的时长(ms) unsigned int extruder_fan_ms; // 挤出机风扇工作的时长(ms)}heater_fan_work_time_t;// 加热头和风扇的设备文件int fd_heater_fan;// pid调节后期待的恒温温度// 挤出头的目标温度float extruder_target_temp = 10;// pid系数float Kp = DEFUALT_Kp;float Ki = DEFAULT_Ki;float Kd = DEFAULT_Kd;float Kc = DEFAULT_Kc;// 读取指定通道的ad值// @channel 通道号// @adc_p 读到的ad值// @ret 成功 or 失败int temp_get_ad(int channel, UINT16 *adc_p){ const char ch1_path[] = {"/sys/bus/spi/drivers/TM7705/spi0.1/ch1"}; const char ch2_path[] = {"/sys/bus/spi/drivers/TM7705/spi0.1/ch2"}; const char *dev_file_path = NULL; int fd = 0; int ret = 0; unsigned int value = 0; char buff[TEMP_BUFF_SIZE] = {0}; // 不同的通道对应/sys下不同的文件 if (TM7705_CH_1 == channel) { dev_file_path = ch1_path; } else { dev_file_path = ch2_path; } fd = open(dev_file_path, O_RDONLY); if (-1 == fd) { printf("[%s] open device file fail.\n", __FUNCTION__); return ERROR; } memset(buff, 0, TEMP_BUFF_SIZE); ret = read(fd, buff, TEMP_BUFF_SIZE-1); if (0 > ret) { printf("[%s] not read data. ret=%d\n", __FUNCTION__, ret); close(fd); return ERROR; } sscanf(buff, "%u\n", &value); value = value >> 6;// printf("[%s] value=%u, buff=%s\n", __FUNCTION__, value, buff); close(fd); if (!TEMP_IS_VALID_AD(value)) { printf("[%s] adc convert fail. ad=%u\n", __FUNCTION__, value); return ERROR; } *adc_p = value; // 输出ad值 return SUCCESS;}// 根据adc值计算温度值// ntc热敏电阻的阻值温度曲线被分为n段,每段可以近似为直线,// 所以温度值的计算就转变为查表再计算// @ad ad值(取值范围为0-1023)// @temp_p 温度值,单位摄氏度// @ret 成功 or 失败int temp_calc_from_ad(UINT16 ad, float *temp_p){ float celsius = 0.0; // 温度值,单位摄氏度 int i = 0; // 判断adc值是否在量程范围内 if (!TEMP_IS_VALID_AD(ad)) { return ERROR; } // 判断是否在表格所表示的范围内 if (ad < temptable[0][0]) // 小于表格的最小adc { *temp_p = temptable[0][1]; // 取最小值 return SUCCESS; } if (ad > temptable[NUMTEMPS-1][0]) // 大于表格的最大adc { *temp_p = temptable[NUMTEMPS-1][1]; // 取最大值 return SUCCESS; } // 查表 // 这里是从adc由低到高,逐个区间进行比较,没有采用折半查找 for (i=1; i
current_diff || 0 == target_temp) { pid = PID_MIN; i_reset = TRUE; printf("[%s] target_temp=%f, current_temp=%f, pid=%f, current temp is too high, heater not work\n", __FUNCTION__, target_temp, current_temp, pid); return pid; } // 当前温度在目标温度附近时,使用pid算法控制温度 else { // 判断是否复位积分计算过程 // 当温度偏差在区间[-PID_FUNCTIONAL_RANGE, PID_FUNCTIONAL_RANGE]内才积分 if (TRUE == i_reset) { i_reset = FALSE; diff_sum = 0.0; // 复位偏差累加和 } // 计算比例项 p_term = Kp * current_diff; // 计算积分项 diff_sum += current_diff; diff_sum = constrain_float(diff_sum, diff_sum_min, diff_sum_max); // 限制积分项的范围 i_term = Ki * diff_sum; // 计算维持功率项 // 当温度不同时,散热快慢也不同,此项起抵消散热维持温度的作用,可增加系统稳定性 c_term = Kc * target_temp; // 计算pid pid = p_term + i_term + d_term + c_term; // 积分分离 if (((PID_MAX < pid) && (0 < current_diff)) || ((PID_MIN > pid) && (0 > current_diff))) { diff_sum -= current_diff; // 取消当前的积分,采用上一次的积分 } // 限制pid的范围 pid = constrain_float(pid, PID_MIN, PID_MAX); if (PID_ACTION_MIN > pid) { pid = 0; } printf("[%s] target_temp=%f, current_temp=%f, pid=%f, Kp=%f, Ki=%f, Kd=%f, Kc=%f, p_term=%f, i_term=%f, d_term=%f, c_term=%f\n", __FUNCTION__, target_temp, current_temp, pid, Kp, Ki, Kd, Kc, p_term, i_term, d_term, c_term); return pid; } }// 将pid转换为pwm值,并传给驱动执行// @pid pid值,取值范围[0,1]void temp_pid_to_pwm(float pid){ heater_fan_work_time_t work_time = {0}; work_time.extruder_heater_ms = HEATER_FAN_PWM_TIME_MS*pid; work_time.extruder_fan_ms = HEATER_FAN_PWM_TIME_MS/2; // 恒温过程,没必要让散热风扇全速运行,增加加热头的? write(fd_heater_fan, &work_time, sizeof(heater_fan_work_time_t)); return ;}// 温度控制的线程// 通过读取当前温度,再用pid算法控制加热,使温度恒定在指定的值上void *temp_thread_fn(void *arg){ float temp = 0.0; // 采集的温度值 float pid = 0.0; // 根据温度计算得到的pid值,取值范围[0,1] int ret = ERROR; if (SUCCESS != temp_init()) { return NULL; } while (1) { usleep(500*1000); // 500ms // 采集温度 ret = temp_get(&temp); if (SUCCESS != ret) { // 采集失败 temp_stop_heater(); // 停止加热,开启散热风扇 printf("[%s] temp_get fail. ret=%d\n", __FUNCTION__, ret); continue; } // 计算pid pid = temp_get_pid(temp); // 将pid转换为pwm值,并传给驱动执行 temp_pid_to_pwm(pid); }}// 设置挤出头目标温度// @target_temp 挤出头目标温度void temp_set_extruder_target_temp(float target_temp){ extruder_target_temp = target_temp; return ;}// 打印挤出头目标温度void temp_print_extruder_target_temp(void){ printf("extruder target temp=%f\n", extruder_target_temp); return ;}// 设置PID系数Kpvoid temp_set_Kp(float new_Kp){ Kp = new_Kp; return ;}// 设置PID系数Kivoid temp_set_Ki(float new_Ki){ Ki = new_Ki; return ;}// 设置PID系数Kdvoid temp_set_Kd(float new_Kd){ Kd = new_Kd; return ;}// 设置PID系数Kcvoid temp_set_Kc(float new_Kc){ Kc = new_Kc; return ;}// 打印PID系数void temp_print_Kp_Ki_Kd_Kc(void){ printf("PID para: Kp=%f, Ki=%f, Kd=%f, Kc=%f\n", Kp, Ki, Kd, Kc); return ;}
重点关注函数temp_get_pid()

演示视频

pid整定效果

http://www.tudou.com/programs/view/8P4UBjvMjGk

pid整定过程(先调比例项系数,再加入微分项,再加入积分项,最后选择性加入维持功率项)

http://www.tudou.com/programs/view/KnaVRQamEG0

发现土豆给转码之后视频画面不是那么清晰了,现在通过网盘分享,链接:http://pan.baidu.com/s/1ckTVCa 密码:iz6b

注意观察温度变化情况,特别是进入pid调整范围(目标温度附近5度),第一个波峰的温度值,同时仔细观察比例项、积分项和微分项是怎样随温度变化而变化的,他们之间又是怎样制约和协调的,最终是温度稳定,同时pid值也基本稳定在一个值附近,那是散热和加热基本平衡。

转载地址:http://vestb.baihongyu.com/

你可能感兴趣的文章
分级解析对Linux服务器的攻击
查看>>
最好的入侵linux教程
查看>>
最好的入侵linux教程基本知识
查看>>
入侵UNIX和Linux服务器入门
查看>>
Linux服务器如何防范SYN Attack攻击
查看>>
Linux的安全设置技巧
查看>>
对Linux服务器平台如何安全保护
查看>>
Tcpdump的小经验
查看>>
17条笑死人的短信
查看>>
网络测试及故障诊断方法及工具 v0.1b
查看>>
linux服务器历险之linux安全设置
查看>>
Linux 性能调优的几种方法(from cu,ibm)
查看>>
Linux 性能监测工具及调优介绍(from cu)
查看>>
MySQL中SQL优化和架构设计的一些简单想法
查看>>
Mysql优化合集
查看>>
MySQL优化实例
查看>>
浅析大型网站的架构[转载]
查看>>
负载均衡技术全攻略
查看>>
从LiveJournal后台发展看大规模网站性能优化方法
查看>>
awk学习笔记
查看>>