系统辨识(PID调参)

PID简述:PID控制器简述(附代码)-CSDN博客

本篇文章将用最简单的语言讲解系统辨识,让一个小白快速对系统辨识有一个了解。因为本文以简单为主,所以存在一定的不严谨性。

首先,系统辨识顾名思义就是分析出一个未知的系统,如电机。通过系统辨识我们可以获得系统的传递函数,构建输入和输出的关系,然后利用simulink中的PID控制器进行系统调参。

以云台为例,在智能车上的云台一般有YAW轴和PITCH轴。我们先对YAW轴电机进行辨识,在辨识的时候我们一般会用到正弦扫频信号(由于很多小白就是卡在正弦扫频信号这一步,所以作者会免费提供keil5的C语言代码),一般我们是发给电机一个目标速度,得到电机的反馈速度(首先我们要根据经验调PID参数,使系统有一个较好的跟随效果效果,建议只用P)。

然后我们将目标速度和电机反馈速度用串口助手输出出来(作者使用的VOFA),我们将数据保存为CSV格式并输入到MATLAB中。

点击打开,选择保存的CSV文件即可,改为列向量,导入成MATLAB的变量即可。

利用MATLAB中的系统辨识工具箱system identification ,将数据导入,即可分析出系统的传递函数。如果我们不确定传递函数的零点和极点数量也没有关系,该工具箱可以帮我们自动分析出来。

我们点击左上侧的Import data,选择Time domain data...

输入input和output,Start Time改为0,Sample time根据自己采样时间更改,作者是0.04。

选择Select range功能。

               选择Transfer Function Models...传递函数模型。

得到传递函数之后我们变可以在simulink中建模,利用PID控制器设置自己的需求,让其自动调节出PID参数。注意,PID控制器不仅会调节参数,还会有一个低通滤波,在代码中我们最好也加上低通滤波。

下图为simulink中PID控制器的自动调节页面,上方可以根据自己的需求选择响应时间和瞬态特性,然后更新模块。该页面在打开PID控制器之后,点击右下角的“调节”按键即可打开。

注:受各方面影响我们辨识的效果可能并不好,所以根据PID控制原理经验调参也是非常重要的。

正弦扫频函数:

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "can.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "math.h"
#include "arm_math.h"
#include "struct_typedef.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
#define get_motor_measure(ptr, data)                                    \
    {                                                                   \
        (ptr)->last_ecd = (ptr)->ecd;                                   \
        (ptr)->ecd = (uint16_t)((data)[0] << 8 | (data)[1]);            \
        (ptr)->speed_rpm = (uint16_t)((data)[2] << 8 | (data)[3]);      \
        (ptr)->given_current = (uint16_t)((data)[4] << 8 | (data)[5]);  \
        (ptr)->temperate = (data)[6];                                   \
    }
			
#define pi 3.1415926535
/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
uint8_t Rx_data[8];
int cnt_w,cnt_t,cnt_T;
		
typedef struct  motor_struct
{
    uint16_t ecd;
    int16_t speed_rpm;			//角速度
    int16_t given_current;
    uint8_t temperate;
    int16_t last_ecd;
} motor_measure_t;

motor_measure_t Motor_measure;
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
CAN_TxHeaderTypeDef CAN1_Txheader1;
CAN_RxHeaderTypeDef Rx_Header;		//数据帧帧头

float speed;

float w[64] = {1,1.499,2,2.5,3.0,3.496,4,4.504,5,5.494,5.988,6.493,6.993,7.518,8,8.474,9.009,9.523,10,10.526,10.989,11.494,12.048,12.500,12.987,13.513,14.084,14.492,14.925,15.384,15.873,16.393,16.949,17.543,17.857,18.518,18.867,19.607,20,20.408,20.833,21.276,22.222,23.809,26.315,27.777,30.303,32.258,34.482,35.714,38.461,40,50,58.823,71.428,76.923,90.909,100,111.111,125,200,250,333.333,500};
float T[64] = {1000,667,500,400,333,286,250,222,200,182,167,154,143,133,125,118,111,105,100,95,91,87,83,80,77,74,71,69,67,65,63,61,59,57,56,54,53,51,50,49,48,47,45,42,38,36,33,31,29,28,26,25,20,17,14,13,11,10,9,8,5,4,3,2};
float data[8000];
/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
extern DMA_HandleTypeDef hdma_usart3_tx;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
//滤波器初始化
void can_filter_init(void)
{
    CAN_FilterTypeDef can_filter_st;
 
    can_filter_st.FilterActivation = ENABLE;
    can_filter_st.FilterMode = CAN_FILTERMODE_IDMASK;
    can_filter_st.FilterScale = CAN_FILTERSCALE_32BIT;
    can_filter_st.FilterIdHigh = 0x0000;
    can_filter_st.FilterIdLow = 0x0000;
    can_filter_st.FilterMaskIdHigh = 0x0000;
    can_filter_st.FilterMaskIdLow = 0x0000;
	
    can_filter_st.FilterBank = 0;
    can_filter_st.FilterFIFOAssignment = CAN_RX_FIFO0;
    HAL_CAN_ConfigFilter(&hcan1, &can_filter_st);
	HAL_CAN_Start(&hcan1);
	HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING);
	
	can_filter_st.SlaveStartFilterBank = 14;   			
    can_filter_st.FilterBank = 14;						
    HAL_CAN_ConfigFilter(&hcan2, &can_filter_st);
    HAL_CAN_Start(&hcan2);																									//使能CAN2
    HAL_CAN_ActivateNotification(&hcan2, CAN_IT_RX_FIFO0_MSG_PENDING);			//CAN接收中断的使能
}



pid_type_def Motor_pid;
float PID[5] = {5,0.0,0.0,25000,6500};
uint8_t TX_message[8];
uint8_t a=0;
/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
	HAL_CAN_GetRxMessage(hcan,CAN_RX_FIFO0,&Rx_Header,Rx_data);	
	if(hcan->Instance == CAN2)
	{
		if(Rx_Header.StdId == 0x000)
			get_motor_measure(&Motor_measure,Rx_data);//获取电机数据
	}
}

/*正弦扫频函数生成*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM2)
	{
		cnt_t++;
		speed = 300*arm_sin_f32(2*pi/1000.0*w[cnt_w]*cnt_t);
		if(cnt_t >= T[cnt_T])
		{
			cnt_t = 0;
			cnt_T++;
			cnt_w++;
		}
		if(cnt_T>=64)		speed = 0;
		PID_calc(&Motor_pid,Motor_measure.speed_rpm,speed);
		if(a==0) Motor_pid.out=0;
		
		TX_message[0] = (int16_t)Motor_pid.out>>8;
		TX_message[1] = (int16_t)Motor_pid.out;
		TX_message[2] = (int16_t)Motor_pid.out>>8;
		TX_message[3] = (int16_t)Motor_pid.out;		
		TX_message[4] = (int16_t)Motor_pid.out>>8;
		TX_message[5] = (int16_t)Motor_pid.out;
		TX_message[6] = (int16_t)Motor_pid.out>>8;
		TX_message[7] = (int16_t)Motor_pid.out;
		
		HAL_CAN_AddTxMessage(&hcan2,&CAN1_Txheader1,TX_message,0);
	}
}
/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	CAN1_Txheader1.DLC = 0x08;
	CAN1_Txheader1.RTR = CAN_RTR_DATA;
	CAN1_Txheader1.IDE = CAN_ID_STD;
	CAN1_Txheader1.StdId = 0x000; //标识符
	PID_init(&Motor_pid,PID_POSITION,PID,PID[3],PID[4]);
  /* 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_DMA_Init();
  MX_CAN1_Init();
  MX_CAN2_Init();
  MX_TIM2_Init();
  MX_USART3_UART_Init();
  MX_USART6_UART_Init();
  /* USER CODE BEGIN 2 */
  can_filter_init();
  HAL_TIM_Base_Start_IT(&htim2);
  HAL_CAN_Start(&hcan1);
  HAL_CAN_Start(&hcan2);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

作者也是在学习之后写下此篇文章,能力有限,有错误之处还望指正。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

J-TS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值