这篇PID的调制就知识我自己个人对于PID的理解了,看了B站好多大佬的视频所以有问题请大家见谅,也请大家多多指正。
这里给大家介绍一个学习PID现象的网页
https://pid-simulator-web.skythinker.top/
首先我们要知道,DJM3508+C620电调的反馈值上的编码值是相对编码值,所以我们要将相对编码值转化为绝对编码值
这里给大家提供一个思路代码
cpp
void CAN_GetMotorData(motor_measure_t * motor )
{
if(motor->ecd - motor->last_ecd>4096)
{
motor->circle--;
}
else if(motor->ecd - motor->last_ecd< -4096)
{
motor->circle++;
}
//计算转动的绝对编码值
motor->encoder = motor->circle*8192+motor->last_ecd;
//RPM换算到rad/s
motor ->speed_rpm = (motor ->speed_rpm* 3.14)/60;
//解算角度
motor ->angle = (double)motor->encoder/8192*2*3.14;
motor->last_ecd = motor->ecd;
}
这个代码的转换思路大致是,电机转动的速度是有最多上线的,也就是说在我的测量时间下,两次的差值不可能超过半圈,所以默认为超过半圈就是淘券了也就是转完一圈了。
然后再下面就是PID的基本代码了
大家有不懂得可以看我前面的文章,但是我想告诉大家的是PID是一种控制算法,以结果为准,不用把所有的附加算法全部加上,要根据现象添加算法
cpp
#include "PID.h"
PID_typedef PID_speed =
{
.Kp = 5,
.Ki = 0.8,
.Kd = 5,
.Max_iout = 100,
.Max_out = 16384,
};
PID_typedef PID_angle =
{
.Kp = 0.4,
.Ki = 0.3,
.Kd = 0.3,
.Max_iout = 10,
.Max_out = 450,
};
float PID_Update(PID_typedef *PID1)
{
PID1->error[1] = PID1->error[0];
PID1->error[0] = PID1->target - PID1->Actual;
//LimitMax(&PID->Iout, PID->Max_iout);
//if (PID->error[0] < 0)
//PID->error[0] = -PID->error[0];
//else
// return PID->error[0];
//if(PID->error[0] < PID->Ki_divider)
{
PID1->Iout += PID1->Ki * PID1->error[0];
}
//else
{
//float fast_Iout = PID->fast_Ki * (PID->error[0] - PID->error[1]);
//LimitMax(&fast_Iout, PID->Max_fast_iout);
//PID->Iout += fast_Iout;
}
LimitMax(&PID1->Iout, PID1->Max_iout);
PID1->D_item = (PID1->error[0] - PID1->error[1]);
PID1->Dout = PID1->Kd * PID1->D_item;
LimitMax(&PID1->Iout, PID1->Max_out);
PID1->OUT = PID1->Kp * PID1->error[0] + PID1->Iout + PID1->Dout;
LimitMax(&PID1->OUT, PID1->Max_out);
return PID1->OUT;
}
cpp
#ifndef PID_H
#define PID_H
#include "main.h"
typedef struct
{
float Kp; /* 比例系数 Proportional coefficient */
float Ki; /* 积分系数 Integral coefficient */
float fast_Ki; /* 快速积分系数 Fast integral coefficient */
float Kd; /* 微分系数 Derivative coefficient */
float Actual; /* 测量值 Measured value */
float target; /* 目标值 Target value */
float error[3]; /* 误差数组 Error array */
float Pout; /* 比例输出 Proportional output */
float Iout; /* 积分输出 Integral output */
float D_item; /* 微分项 Derivative item */
float Dout; /* 微分输出 Derivative output */
float OUT; /* 总输出 Total output */
float Max_iout; /* 积分输出限幅 Integral output limit */
float Max_fast_iout; /* 快速积分输出限幅 Fast integral output limit */
float Max_out; /* 总输出限幅 Total output limit */
float Ki_divider; /* 积分分离阈值 Integral separation threshold */
} PID_typedef;
float PID_Update(PID_typedef *PID1);
#endif /* PID_H */
cpp
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2026 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "can.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "bsp_can.h"
#include "CAN_receive.h"
#include "PID.h"
#include <stdio.h>
/* USER CODE END Includes */
void LimitMax(float *value, float max_value)
{
if(*value > max_value)
*value = max_value;
else if(*value < -max_value)
*value = -max_value;
}
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
extern PID_typedef PID_angle;
extern PID_typedef PID_speed;
extern motor_measure_t motor_chassis[7];
float out_angle = 0 ;
float out_speed = 0 ;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 10);
while((huart1.Instance->SR & USART_SR_TXE) == 0)
{
;
}
huart1.Instance->DR = *(uint8_t*)&ch;
return ch;
}
/* 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_CAN1_Init();
MX_CAN2_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
can_filter_init();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == 0)
{
HAL_Delay(20);
while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == 0);
PID_angle.target += 5000;
// PID_Motor1.Target += (6.28*0.5);
}
out_angle = PID_Update(&PID_angle);
PID_speed.target = out_angle;
out_speed = PID_Update(&PID_speed);
CAN_cmd_chassis(500,out_speed,500,500);
// CAN_cmd_chassis(500,400,500,500);
HAL_Delay(10);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 6;
RCC_OscInitStruct.PLL.PLLN = 168;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */