基于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直流电机调速系统能够实现良好的控制效果,在实际应用中可根据具体需求进一步优化和调整。



更多推荐


所有评论(0)