cancel
Showing results for 
Search instead for 
Did you mean: 

CMSIS-DSP PID help

matheuscaltran
Associate II

I'm using the stm32f429 discovery, I made a PWM control and tested it with a potentiometer and it worked as expected with 1mhz. Now I need to do the temperature control, I'm using a MAX31865 with PT100 and heating a resistance with the PWM output (this part is working very well) now for the PID it's not working right, I'm using:

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
 
#include "MATH/MATH.h"//MAP
 
#include "MAX31865_lib.h"//MAX31865 PT100
 
#include "arm_math.h"//PID
 
/* USER CODE BEGIN 0 */
unsigned long Millis;
 
unsigned long TempoMillis;
unsigned long TempoMillis1;
 
 
uint16_t potenPWM;
uint16_t potenMAP;
 
extern bool MAX31865_Sensor_Error;
float PT100_Temperature = 0.0f;
 
uint16_t INT_PT100_Temperature;
 
 
//********************PWM CONTROL BY POTENTIOMETER USING ADC IT********************
 
// void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
// {
//   potenMAP = HAL_ADC_GetValue(&hadc1);
  /*If continuousconversion mode is DISABLED uncomment below*/
  //HAL_ADC_Start_IT (&hadc1);
 
// }
 
 
/* PID error */
float pid_error;
float PID_Temperatura_setpoint = 75.50;
float Tempetura_current;
float duty;
/* USER CODE END 0 */
 
/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
 
  /* USER CODE END 1 */
 
  /* MCU Configuration--------------------------------------------------------*/
 
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
 
  /* USER CODE BEGIN Init */
 
  /* USER CODE END Init */
 
  /* Configure the system clock */
  SystemClock_Config();
 
  /* USER CODE BEGIN SysInit */
 
  /* USER CODE END SysInit */
 
  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM1_Init();
  MX_TIM2_Init();
  MX_ADC1_Init();
  MX_SPI1_Init();
  /* USER CODE BEGIN 2 */
 
  MAX31865_Init(3);
 
  HAL_TIM_Base_Start(&htim1);
  HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
 
  HAL_ADC_Start_IT (&hadc1);
 
 
  //*************************************PID********************************************
 
  /* ARM PID Instance, float_32 format */
   arm_pid_instance_f32 PID;
 
   /* Set PID parameters */
   /* Set this for your needs */
   PID.Kp = 100;        /* Proporcional */
   PID.Ki = 15;        /* Integral */
   PID.Kd = 0;        /* Derivative */
 
   /* Initialize PID system, float32_t format */
   arm_pid_init_f32(&PID, 1);
 
  /* USER CODE END 2 */
 
  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */
 
    /* USER CODE BEGIN 3 */
  Millis = __HAL_TIM_GET_COUNTER(&htim1);
 
  if(Millis - TempoMillis >= 500)
      {
  PT100_Temperature = MAX31865_Get_Temperature();
 
if (PT100_Temperature >= 0) {
PT100_Temperature = PT100_Temperature + 1.77;
} else {
PT100_Temperature = -PT100_Temperature + 1.77;
}
 
  TempoMillis = Millis;
      }
 
//****************PWM CONTROL BY POTENTIOMETER_Conversion_Or_IT********************
  //HAL_ADC_Start(&hadc1);
// HAL_ADC_PollForConversion(&hadc1, 100);
  //potenMAP = HAL_ADC_GetValue(&hadc1);
  //potenPWM = MAP(potenMAP, 0, 4095, 0, 1000);
// __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,potenPWM);
 
 
//****************************************PID****************************************
  Tempetura_current = PT100_Temperature;
 
  pid_error = (PID_Temperatura_setpoint - Tempetura_current);
  duty = arm_pid_f32(&PID, pid_error);
 
if(duty<0){
duty=0;
}
if(duty >1000){
duty =1000;
}
 
  __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_1,duty);
 
 
  }
  /* USER CODE END 3 */
}

I made a video to show how the PID is behaving:
2 REPLIES 2
InsignificantBit
ST Employee

Hi.

I suspect that the controller is just not tuned correctly and there is wind-up condition happening.

Look up Integral windup and anti-windup techniques.

I did other tests but instead of the PWM value of 1000 for 4096

based on the test I did and because it blows the scale

The PidOut variable is a float, so the maximum value of the float is: 3.402823466 E + 38 and the minimum value will be -3.402823466 E + 38

When the setpoint temperature reaches the PidOut variable, it reaches a value much higher than 4096 (500x higher) because it is a float, then it starts to decrease the value but takes a while to reach below 4096

(it takes a long time to reach the duty value)

matheuscaltran_0-1704493342352.png

Video showing:



With this, there would be some way to edit the maximum and minimum value of PidOut = arm_pid_f32(&PID, pid_error); specifically the arm_pid_f32 function

 

With this, there would be some way to edit the maximum and minimum value of PidOut = arm_pid_f32(&PID, pid_error); specifically the arm_pid_f32 function

I can also use arm_pid_q31 and create a MAP (https://deepbluembedded.com/map-function-embedded-c/)
but I couldn't get arm_pid_q31 to work even transforming all values into int