综合技术
直播中

杨兰兰

7年用户 221经验值
私信 关注
[问答]

请问PID和仿人控制谁更好?

硬件:
1。用可控硅控制4.5KW电炉 用K型热电偶采集温度,采用cs1242做温度转换,可以到正负一度的精度
实验目标:
在300度到1000度内可对任意设定的温度恒温,精度先做到+/-1度吧
基本的控制实现方法:
因为是对加热的炉子温度进行控制,属于滞后效应系统,所以采样周期先定为2秒(这里指的是PID计算的周期,注意我的温度采样是实时的),所以CPU外部中断次数为15次/S,对应的功率计算结果输出为0~255,就是说把这2秒钟划分为255等份,根据计算的结果来决定在这2秒钟内应该加热多少等份

/******************************************************************************
FILE:       FUZZY.C
POPURSE:
WRITER:     Xukaiming
DATE:       2007.03.08
******************************************************************************/
#include "main.h"
#include "task.h"
#include "fuzzy.h"
#include "ied_ctrl.h"
#include "math.h"
#include "x5043.h"
#include "manctrl.h"
#define ERRORCNT  9                        //误差记录
#define DERRORCNT 10                //误差变化率记录
//#define DOOROPENSPEED  -15L        //开门时的升温速度,如果低于此温度,认为电阻丝的热量完全散发出来或者开门升温
xdata long DOOROPENSPEED =  - 15L;
#define MAXNEGINTERG   (-200L*KI/Ki)
extern code unsigned int K_Temp_Tab[];
typedef struct AI_CONTROL
{
  long gDest; //目标温度的AD值
  long CTEMP; //开始控制温度
  long Error[ERRORCNT]; //偏差
  long dErr[DERRORCNT]; //偏差变化率        
  long ECSUM; //10S内的偏差变化率之和               
  long SumErrLimit; //加热初值                        
  long PreviewOut;
  long du;
  long DoorOpenValue; //保存炉子门状态         
  char LowSpeedCnt;
  unsigned int iDestTemp; //目标温度值
};
#define Kp                15                           //输出变量u比例因子
#define Ki                1/10                                 //衰减系数;               
#define KI                15
//Kp 变小的时候 ki要变大        
xdata struct AI_CONTROL Ai_CTRL;
void TaskFuzzy(void)
{
  char cnt;
  _nop_();
  if (IED.lADTemp > MAX_TEMP)
  //超温保护
  {
    SetPWM(PWM_PITCED);
    return ;
  }
  //求偏差
  for (cnt = ERRORCNT - 1; cnt > 0; cnt--)
  {
    Ai_CTRL.Error[cnt] = Ai_CTRL.Error[cnt - 1];
  } //保存上次偏差值
  Ai_CTRL.Error[0] = (long)(((Ai_CTRL.gDest - IED.lADTemp) / KC));
  for (cnt = DERRORCNT - 1; cnt > 0; cnt--)
  {
    Ai_CTRL.dErr[cnt] = Ai_CTRL.dErr[cnt - 1];
  } //保存上次偏差率值
  Ai_CTRL.dErr[0] = Ai_CTRL.Error[0] - Ai_CTRL.Error[1]; //计算偏差变化率
  Ai_CTRL.ECSUM = Ai_CTRL.dErr[0] + Ai_CTRL.dErr[1] + Ai_CTRL.dErr[2] +
    Ai_CTRL.dErr[3] + Ai_CTRL.dErr[4]; //10s的温升速率          =iol               
  if (Ai_CTRL.Error[0] < Ai_CTRL.CTEMP)
  {
    if (((Ai_CTRL.Error[0] *Ai_CTRL.dErr[0]) > 0) || ((Ai_CTRL.Error[0] == 0)
      && (Ai_CTRL.dErr[0] != 0)))
    //误差变大的情况
    {
      Ai_CTRL.SumErrLimit += Ai_CTRL.Error[0]; //误差变大的时候,求积分                        
      if (Ai_CTRL.SumErrLimit < MAXNEGINTERG)
      //限幅,如果超过负的最大值, 保持为负的最大值
        Ai_CTRL.SumErrLimit = MAXNEGINTERG;
      ////////////////////////////////////////////////////////////
      Ai_CTRL.du = Ai_CTRL.Error[0] *Kp + Ai_CTRL.SumErrLimit * Ki / KI * Kp;
        //增益抑制模式                                 //                                
    }
    else
    //开环保持模式
    {
      if (((Ai_CTRL.Error[0] *Ai_CTRL.dErr[0]) < 0) || (Ai_CTRL.dErr[0] == 0))
      //误差变小的情况
      {
        Ai_CTRL.du = Ai_CTRL.SumErrLimit * Ki / KI * Kp;
      }
      else
      {
        Ai_CTRL.du = Ai_CTRL.PreviewOut;
      }
    }
  }
  else
    Ai_CTRL.du = PWM_PERIOD;
  //升温
  if (Ai_CTRL.du < 0)
    Ai_CTRL.du = 0;
  if (Ai_CTRL.du > PWM_PERIOD)
    Ai_CTRL.du = PWM_PERIOD;
  #ifdef _DEBUG
    printf("%ld,", Ai_CTRL.CTEMP);
    printf("%ld,%ld,", Ai_CTRL.Error[0], Ai_CTRL.dErr[0]);
    printf("%ld,%ld,%dn", Ai_CTRL.ECSUM, Ai_CTRL.SumErrLimit, (int)Ai_CTRL.du);
  #endif
  SetPWM((unsigned char)Ai_CTRL.du);
  //保存上次输出
  Ai_CTRL.PreviewOut = Ai_CTRL.du;
}
//functions prototype
/************************************************************************
仿人智能控制器//Humanoid Intelligent Controller
************************************************************************/
/*******************************************************************
模糊控制数据变量
********************************************************************/
void InitFuzzy(void)
{
  Ai_CTRL.DoorOpenValue = 0; //  重新统计升温速度        
  Ai_CTRL.LowSpeedCnt = 0;
  SetPWM(PWM_PITCED);
}
/*********************************************************************
启动高温炉
**********************************************************************/
void CtrlStove(UCHAR cOpen, long lDefTemp, UCHAR cRate)
{
  xdata StableTempTab psTmpTab;
  //停止                                
  SuspendTask(TASK_FUZZY);
  InitFuzzy();
  if (cOpen)
  //启动
  {
    Ai_CTRL.gDest = (((double)(0xFFFFFFUL << 2)) / 5000000UL)
      *K_Temp_Tab[lDefTemp] + 20; //将 目标 温度值 转换 为 AD值
    Ai_CTRL.CTEMP = (1010L - lDefTemp); //控温范围
    ActiveTask(TASK_FUZZY, PWM_SCAN);
  }
}
/**********************************************************************
设置PWM,PWM0控制高温炉
16MHz时,T=2*512/16=64uS,F=42.666KHz,计数周期=256,占空比=0%--99.61%
***********************************************************************/
***it POUT = P1 ^ 3;
char gcPoutTimer =  - 1;
void StopPOut()
{
  POUT = 1;
}
void SetPWM(UCHAR cPeriod)
{
  /*
  CMOD  = 0x00;                                         // Setup PCA timer
  // Configure PCA0 Counter operating mode
  CCAP0L=CCAP0H=cPeriod;                        // Set duty for TCM0
  CCON  =0x40;                        
  CCAPM0=0x42;                                        // Set TCM0 operationg mode                        
   */
  long period;
  StopTimer(&gcPoutTimer);
  POUT = 1;
  period = PWM_SCAN * cPeriod / 255 / 10;
  if (period > 0)
  {
    POUT = 0;
    gcPoutTimer = StartTimer(TIMER_MODE_ONCEROUTINE, period, StopPOut, 0);
  }
}

回帖(6)

汪岑

2019-10-8 07:31:25
没看懂楼主发这帖子想说什么
举报

李星童

2019-10-8 07:37:46
PID算法也没说明白啊?!!!
举报

李青

2019-10-8 07:51:13
我也没看懂...
举报

田硕

2019-10-8 08:06:31
不明觉力。。。
举报

王淑华

2019-10-8 08:15:42
不懂。。。。。。。。。。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分