基于STM32F1的线性自抗扰(LADRC)直流电机调速实现

基于STM32F1的线性自抗扰(LADRC)直流电机调速实现 线性自抗扰LADRC的stm32f1程序实现用编码器反馈控制直流电机调速控制器采用加了TD的LADRC控制效果良好.h和.c分开代码清晰有注释。 有调试说明前言在电机控制领域如何实现精准的调速一直是个重要课题。线性自抗扰控制LADRC以其独特的优势能有效应对系统的不确定性和干扰在直流电机调速中表现出色。本文将分享基于STM32F1的LADRC实现直流电机调速且采用加了TD跟踪微分器的LADRC配合编码器反馈实现良好的控制效果同时代码以.h和.c文件分开编写保证清晰且注释丰富。整体架构整个项目分为硬件和软件两大部分。硬件上主要涉及STM32F1开发板、直流电机以及编码器。编码器用于实时反馈电机的转速信息STM32F1通过读取编码器数据运用LADRC算法计算出合适的控制量来驱动直流电机。线性自抗扰LADRC的stm32f1程序实现用编码器反馈控制直流电机调速控制器采用加了TD的LADRC控制效果良好.h和.c分开代码清晰有注释。 有调试说明软件层面核心代码以.h和.c文件分开编写方便模块化管理和代码复用。代码实现1. 定义LADRC相关参数的头文件 ladrc.h#ifndef _LADRC_H #define _LADRC_H // 定义结构体来存储LADRC的参数 typedef struct { float b0; // 控制增益 float beta01; // TD参数 float beta02; // TD参数 float beta1; // ESO参数 float beta2; // ESO参数 float beta3; // ESO参数 float kp; // 控制律参数 float ki; // 控制律参数 float kd; // 控制律参数 float r; // 跟踪微分器快速因子 float h; // 采样步长 float h0; // TD滤波因子 } LADRC_Parameters; // 定义结构体来存储LADRC的状态 typedef struct { float x1; // TD状态1 float x2; // TD状态2 float z1; // ESO状态1 float z2; // ESO状态2 float z3; // ESO状态3 float u0; // 控制量 float e1; // 误差1 float e2; // 误差2 } LADRC_State; // 初始化LADRC参数 void LADRC_Init(LADRC_Parameters *parameters, LADRC_State *state); // 运行LADRC算法 float LADRC_Run(LADRC_Parameters *parameters, LADRC_State *state, float ref, float feedback); #endif在这个头文件里我们定义了两个结构体一个用来存放LADRC的各种参数比如控制增益b0跟踪微分器TD和扩张状态观测器ESO的参数等。另一个结构体则用来存储LADRC运行过程中的状态变量。同时还声明了初始化函数LADRCInit和运行函数LADRCRun。2. ladrc.c文件实现LADRC算法#include ladrc.h #include math.h // 初始化LADRC参数 void LADRC_Init(LADRC_Parameters *parameters, LADRC_State *state) { state-x1 0; state-x2 0; state-z1 0; state-z2 0; state-z3 0; state-u0 0; state-e1 0; state-e2 0; } // 运行LADRC算法 float LADRC_Run(LADRC_Parameters *parameters, LADRC_State *state, float ref, float feedback) { // TD部分 float fhan; float d parameters-r * parameters-h0; float d0 parameters-h0 * d; float y state-x1 - ref; float a0 parameters-h * state-x2; if (fabs(y) d0) { fhan -parameters-r * (y / fabs(y)); } else { fhan -parameters-r * y / d; } state-x1 state-x1 parameters-h * state-x2; state-x2 state-x2 parameters-h * fhan; // ESO部分 state-e1 state-z1 - feedback; state-z1 state-z1 parameters-h * (state-z2 - parameters-beta1 * state-e1); state-z2 state-z2 parameters-h * (state-z3 - parameters-beta2 * state-e1); state-z3 state-z3 - parameters-h * parameters-beta3 * state-e1; // 控制律部分 state-e2 state-x1 - state-z1; state-u0 state-kp * state-e2 state-kd * (state-x2 - state-z2) state-ki * state-e1; float u (state-u0 - state-z3) / parameters-b0; return u; }在ladrc.c文件中LADRCInit函数对LADRC的状态变量进行初始化将所有状态变量设为0 。LADRCRun函数实现了LADRC的核心算法流程。首先是跟踪微分器TD部分通过fhan函数来安排过渡过程根据误差y的大小调整输出进而更新x1和x2状态。然后是扩张状态观测器ESO部分通过误差e1不断更新z1、z2和z3对系统状态和干扰进行观测。最后在控制律部分结合TD和ESO的输出计算出控制量u。3. 编码器读取及主控制代码 main.c#include stm32f10x.h #include ladrc.h // 假设编码器引脚初始化函数 void Encoder_Init(void) { // 配置定时器及相关引脚为输入捕获模式 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_ICInitTypeDef TIM_ICInitStructure; GPIO_InitTypeDef GPIO_InitStructure; // 使能定时器和GPIO时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // 配置PA6和PA7为复用推挽输出 GPIO_InitStructure.GPIO_Pin GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd GPIO_PuPd_UP; GPIO_Init(GPIOA, GPIO_InitStructure); // 定时器基本配置 TIM_TimeBaseStructure.TIM_Period 65535; TIM_TimeBaseStructure.TIM_Prescaler 0; TIM_TimeBaseStructure.TIM_ClockDivision 0; TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, TIM_TimeBaseStructure); // 输入捕获配置 TIM_ICInitStructure.TIM_Channel TIM_Channel_1; TIM_ICInitStructure.TIM_ICPolarity TIM_ICPolarity_Rising; TIM_ICInitStructure.TIM_ICSelection TIM_ICSelection_DirectTI; TIM_ICInitStructure.TIM_ICPrescaler TIM_ICPSC_DIV1; TIM_ICInitStructure.TIM_ICFilter 0x00; TIM_ICInit(TIM3, TIM_ICInitStructure); TIM_ICInitStructure.TIM_Channel TIM_Channel_2; TIM_ICInit(TIM3, TIM_ICInitStructure); // 使能定时器 TIM_Cmd(TIM3, ENABLE); } // 获取编码器计数值 int16_t Get_Encoder(void) { return TIM3-CNT; } int main(void) { LADRC_Parameters ladrc_params; LADRC_State ladrc_state; float ref_speed 1000; // 设定目标转速 float feedback_speed; float control_value; Encoder_Init(); // 初始化LADRC参数 ladrc_params.b0 1; ladrc_params.beta01 100; ladrc_params.beta02 200; ladrc_params.beta1 100; ladrc_params.beta2 200; ladrc_params.beta3 1000; ladrc_params.kp 1; ladrc_params.ki 0.1; ladrc_params.kd 0.01; ladrc_params.r 100; ladrc_params.h 0.001; ladrc_params.h0 0.001; LADRC_Init(ladrc_params, ladrc_state); while (1) { feedback_speed Get_Encoder(); // 获取当前转速反馈 control_value LADRC_Run(ladrc_params, ladrc_state, ref_speed, feedback_speed); // 将控制值转换为PWM占空比控制直流电机 // 假设这里有个函数Set_PWM来设置PWM占空比 Set_PWM(control_value); } }在main.c文件中首先定义了编码器初始化函数EncoderInit配置定时器和相关引脚为输入捕获模式用于读取编码器数据。GetEncoder函数则用于获取当前编码器的计数值以此来表示电机的转速反馈。在main函数里初始化LADRC参数和状态设定目标转速refspeed。在循环中不断读取编码器反馈的转速feedbackspeed通过LADRCRun函数计算出控制量controlvalue并将其转换为PWM占空比来控制直流电机。调试说明参数调整LADRC算法效果对参数比较敏感。在调试初期可以先使用默认参数运行观察电机的转速响应。如果电机响应过慢或超调过大可以适当调整TD和ESO的参数如beta01、beta02、beta1、beta2、beta3等。kp、ki、kd控制律参数也会影响控制效果kp增大可加快响应速度但可能导致超调ki用于消除稳态误差kd可抑制超调。编码器信号检查确保编码器安装正确输出信号稳定。可以通过示波器观察编码器输出的A相和B相脉冲信号检查其频率和相位关系是否正常。在程序中可以在初始化后打印编码器的初始计数值确认编码器是否正常工作。电机驱动检查检查电机驱动电路是否正常工作确保PWM信号能够正确控制电机转速。可以通过调整PWM占空比观察电机是否有相应的转速变化。通过上述步骤和代码实现基于STM32F1的加TD的LADRC直流电机调速系统能够实现良好的控制效果在实际应用中可根据具体需求进一步优化和调整。