本文为在用龙芯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上实现的。其中TM7705+NTC热敏电阻采集温度的文章之前已经写了,控制加热头的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/GPIO91
struct 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 <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/err.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <linux/delay.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/ls1c_3dprinter_heater_fan.h>
// pwm周期(ms)
#define HEATER_FAN_PWM_TIME_MS (200) // 200ms
enum
{
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;