串级PID控制3508(2)(单环角度环+单环角速度环+串级PID)

这篇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 */
相关推荐
aircrushin29 分钟前
OpenClaw开源生态与AI执行能力的产业化路径
人工智能
是糖糖啊35 分钟前
OpenClaw 从零到一实战指南(飞书接入)
前端·人工智能·后端
踩着两条虫1 小时前
从设计稿到代码:VTJ.PRO 的 AI 集成系统架构解析
前端·vue.js·人工智能
孤烟1 小时前
吓瘫!我用1行代码攻破公司自研AI权限系统,数据裸奔一整夜(附攻击payload+防御源码)
人工智能·ai编程
掘金一周1 小时前
Claude Code 换成了Kimi K2.5后,我再也回不去了 | 掘金一周 3.5
前端·人工智能·agent
vivo互联网技术2 小时前
ICLR2026 | 视频虚化新突破!Any-to-Bokeh 一键生成电影感连贯效果
人工智能·python·深度学习
OpenBayes贝式计算2 小时前
边看、边听、边说,MiniCPM-0-4.5 全双工全模态模型;Pan-Cancer scRNA-Seq 涵盖三种生物学状态单细胞转录数据集
人工智能·深度学习·机器学习
OpenBayes贝式计算3 小时前
教程上新丨基于500万小时语音数据,Qwen3-TTS实现3秒语音克隆及精细调控
人工智能·深度学习·机器学习
CoovallyAIHub3 小时前
开源:YOLO最强对手?D-FINE目标检测与实例分割框架深度解析
人工智能·算法·github