news 2026/7/16 3:13:31

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
串级PID控制3508(2)(单环角度环+单环角速度环+串级PID)

这篇PID的调制就知识我自己个人对于PID的理解了,看了B站好多大佬的视频所以有问题请大家见谅,也请大家多多指正。

这里给大家介绍一个学习PID现象的网页

https://pid-simulator-web.skythinker.top/

首先我们要知道,DJM3508+C620电调的反馈值上的编码值是相对编码值,所以我们要将相对编码值转化为绝对编码值

这里给大家提供一个思路代码

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是一种控制算法,以结果为准,不用把所有的附加算法全部加上,要根据现象添加算法

#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; }
#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 */
/* 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 */
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/15 16:13:44

设计模式Trustworthy Generation:提升RAG信赖度

本文介绍了名为 Trustworthy Generation 的设计模式&#xff0c;旨在提升 RAG 系统生成内容的信赖度&#xff0c;即真实性&#xff08;是否准确、无幻觉、无偏见&#xff09;与完整度&#xff08;是否全面、不遗漏关键信息&#xff09;。文章系统分析了 RAG 信赖度不足的四大根…

作者头像 李华
网站建设 2026/6/30 23:14:47

3步技术突破:Cursor Pro无限体验实现指南

3步技术突破&#xff1a;Cursor Pro无限体验实现指南 【免费下载链接】cursor-free-everyday 完全免费, 自动获取新账号,一键重置新额度, 解决机器码问题, 自动满额度 项目地址: https://gitcode.com/gh_mirrors/cu/cursor-free-everyday 我们如何突破AI编程工具的额度限…

作者头像 李华
网站建设 2026/7/14 18:35:52

【Python】列表|元组

文章目录1. 列表是什么&#xff1f;元组是什么&#xff1f;2. 创建列表3. 访问下标4. 切片操作5. 遍历列表元素6. 新增元素7. 查找元素8. 删除元素9. 连接列表10. 关于元组小结1. 列表是什么&#xff1f;元组是什么&#xff1f; 编程中&#xff0c;经常需要使用变量&#xff0…

作者头像 李华
网站建设 2026/7/4 8:59:10

安卓Recovery完全掌控指南:从准备到排障的系统化方案

安卓Recovery完全掌控指南&#xff1a;从准备到排障的系统化方案 【免费下载链接】Magisk The Magic Mask for Android 项目地址: https://gitcode.com/GitHub_Trending/ma/Magisk 安卓Recovery是设备系统维护的核心工具&#xff0c;第三方Recovery如TWRP更是实现系统备…

作者头像 李华
网站建设 2026/7/4 7:19:47

免费录屏全场景指南:多音源录制与声音同步解决方案

免费录屏全场景指南&#xff1a;多音源录制与声音同步解决方案 【免费下载链接】QuickRecorder A lightweight screen recorder based on ScreenCapture Kit for macOS / 基于 ScreenCapture Kit 的轻量化多功能 macOS 录屏工具 项目地址: https://gitcode.com/GitHub_Trendi…

作者头像 李华
网站建设 2026/7/4 22:03:04

打造专属音乐体验:用NSMusicS构建个性化音乐空间

打造专属音乐体验&#xff1a;用NSMusicS构建个性化音乐空间 【免费下载链接】NSMusicS NSMusicS&#xff08;Nine Songs Music World&#xff1a;九歌 音乐世界&#xff09;&#xff0c;open-source music software 项目地址: https://gitcode.com/GitHub_Trending/ns/NSM…

作者头像 李华