PID算法在电机速度控制上的应用

目录

概述

1 系统硬件框架

1.1 框架介绍

1.2 硬件实物图

2 STM32Cub生成工程

2.1 软件版本信息

2.2  配置参数

​编辑2.3 生成项目

3 PID算法实现

3.1 概念

3.2 代码实现

4 其他功能实现

4.1 设置电机速度

4.2 PID算法控制电机

4.3 功能函数的调用

5 测试

5.1 测试案例1

5.2 测试案例2


源代码下载地址:

PID算法在电机速度控制上的应-测试源码资源-CSDN文库

概述

本文主要介绍使用PID算法实现电机速度的控制,笔者使用IO外部中断测试码盘的脉冲实现测速功能,通过该速度值,应用PID算法实现调制PWM的占空比,以实现电机速度的控制。

1 系统硬件框架

1.1 框架介绍

1) 系统使用光电编码器进行速度测试,具体实现方式可以参看原文:

电机转速计算(基于码盘和IO外部中断)-CSDN博客

2) TIMER7实现定时器功能,其会产生10us的定时器中断,为系统工作提供基准时钟。

3)TIMER8用于产生PWM实现电机速度控制,系统通过电机速度的反馈值以调节PWM的脉冲宽度,以实现电机速度的闭环控制。

1.2 硬件实物图

 使用STM32F103RC作为主控芯片,LN298N用于驱动电机,光电码盘用于测试电机转速。具体的测试实物图如下:

2 STM32Cub生成工程

2.1 软件版本信息

软件名称版本信息
STM32CubeSTM32CubeMX 6.11
STM32 HALSTM32Cube_FW_F1_V1.8.5

2.2  配置参数

1)配置EXTI IO中断,其用测监测编码器的冲击脉冲,选择PC0接口,同时要使能外部中断函数

 使能中断函数

2)配置Timer7,中断间隔为10us,其具体配置参数如下:

 使能中断函数

 3)配置PWM相关的参数和使能通道

定时器相关的参数配置如下,计数周期为10ms

 

 PWM通道相关的参数:

各个通道对应的IO接口如下:

2.3 生成项目

配置完成各个参数后,就可以生成项目,打开项目后,其结构如下:

3 PID算法实现

3.1 概念

PID是一种常用的控制算法,全名为比例-积分-微分控制算法(Proportional-Integral-Derivative Control)。它通过对系统的误差进行比例、积分和微分运算,从而对系统进行控制。

PID控制算法的基本原理是:根据当前系统的误差,分别计算比例、积分和微分项,并将它们加权叠加作为最终的控制量。

具体来说,比例项(Proportional)是根据误差的大小与比例系数的乘积来计算的,它决定了控制量与误差之间的直接关系。比例项越大,控制量的调整越快。

积分项(Integral)是根据误差的累积进行计算的,它可以消除系统存在的静态误差,并且对于系统的稳定性有所影响。积分项越大,控制量的调整越缓慢。

微分项(Derivative)是根据误差的变化率进行计算的,它可以预测误差的未来变化趋势,并提前调整控制量。微分项越大,控制量的调整越灵敏。

PID算法的最终控制量是比例项、积分项和微分项的加权叠加,其中比例系数、积分系数和微分系数可以根据实际需求进行调整,以达到最佳的控制效果。

理想的PID控制算法:

• Kp     ——  比例增益, Kp 与比例度成倒数关系
• Tt      ——  积分时间常数
• TD     ——  微分时间常数
• u(t)——  PID 控制器的输出信号
• e(t)——  给定值 r(t)与测量值误差

3.2 代码实现

代码117行: 计算目标值与实际值的误差

代码124行:累计误差值

代码127行:实现PID的功能

代码130行: 传递误差值

实际代码:

typedef struct
{
    float target_val;       //目标值
    float actual_val;       //实际值
    float err;              //定义偏差值
    float err_last;         //定义上一个偏差值
    float Kp,Ki,Kd;         //定义比例、积分、微分系数
    float integral;         //定义积分值
}_pid;


/**
  * @brief  速度PID算法实现
  * @param  actual_val:实际值
    @note   无
  * @retval 通过PID计算后的输出
  */
float pid_speed_realize(_pid *pid, float actual_val)
{
    /*计算目标值与实际值的误差*/
    pid->err = pid->target_val - actual_val;

    if((pid->err<0.2f )&& (pid->err>-0.2f))
    {
        pid->err = 0.0f;
    }

    pid->integral += pid->err;    // 误差累积

    /*PID算法实现*/
    pid->actual_val = pid->Kp*pid->err+pid->Ki*pid->integral+pid->Kd*(pid->err-pid->err_last);

    /*误差传递*/
    pid->err_last=pid->err;

    /*返回当前实际值*/
    return pid->actual_val;
}

4 其他功能实现

4.1 设置电机速度

代码80行: 设置通道1的占空比值

代码81行: 设置通道2的占空比值为0,用于控制方向

实际代码:

void set_motor_speed( uint16_t actual_speed )
{
    HAL_TIM_SetPWM_Pulse( actual_speed, TIM_CHANNEL_1);
    HAL_TIM_SetPWM_Pulse( 0, TIM_CHANNEL_2);
}

4.2 PID算法控制电机

代码195行:获取当前电机的转速

代码198行:比较实际值和期望值的差值,便于将实际值控制在一定的范围之内

代码201行:使用实际值进行PID运行,计算出占空比的值,以调节转速

代码205行:设置电机速度

 实际代码:

void motor_pid_control(void)
{
    float actual_speed, cal_speed ;
    uint8_t value;
    bool is_match;
    uint8_t buff[16];
    uint32_t delta_value;
    
    actual_speed = get_motor_speed();
    cal_speed = pid_get_target(&pid_speed);
    
    is_match = abs((int)((actual_speed- cal_speed)*10)) > 10 ? false : true;
    if( !is_match )
    {
        cal_speed = pid_speed_realize( &pid_speed,actual_speed);    // 进行 PID 计算
        cal_speed = convet_speed( cal_speed );
        cal_speed = (cal_speed > PWM_PERIOD_MAX_COUNT) ? PWM_PERIOD_MAX_COUNT : cal_speed;    // 速度上限处理

        set_motor_speed(cal_speed);                                 // 设置 PWM 占空比
    }
    
    #if defined(PID_ASSISTANT_EN)
        value = (uint8_t)actual_speed;
        buff[0] =  value;
        protocol_computer_value(SEND_FACT_CMD, CURVES_CH1, buff, 1);               // 给通道 1 发送实际值
    #else
        printf("实际值:%.02f 目标值:%.0f\n", actual_speed, pid_get_target(&pid_speed));      // 打印实际值和目标值
    #endif
}

4.3 功能函数的调用

代码211行:计算电机的转速

代码217行:电机PID控制函数

 实际源码:

void motor_pid_control(void)
{
    float actual_speed, cal_speed ;
    uint8_t value;
    bool is_match;
    uint8_t buff[16];
    uint32_t delta_value;
    
    actual_speed = get_motor_speed();
    cal_speed = pid_get_target(&pid_speed);
    
    is_match = abs((int)((actual_speed- cal_speed)*10)) > 10 ? false : true;
    if( !is_match )
    {
        cal_speed = pid_speed_realize( &pid_speed,actual_speed);    // 进行 PID 计算
        cal_speed = convet_speed( cal_speed );
        cal_speed = (cal_speed > PWM_PERIOD_MAX_COUNT) ? PWM_PERIOD_MAX_COUNT : cal_speed;    // 速度上限处理

        set_motor_speed(cal_speed);                                 // 设置 PWM 占空比
    }
    
    #if defined(PID_ASSISTANT_EN)
        value = (uint8_t)actual_speed;
        buff[0] =  value;
        protocol_computer_value(SEND_FACT_CMD, CURVES_CH1, buff, 1);               // 给通道 1 发送实际值
    #else
        printf("实际值:%.02f 目标值:%.0f\n", actual_speed, pid_get_target(&pid_speed));      // 打印实际值和目标值
    #endif
}

5 测试

5.1 测试案例1

PID参数设置如下类型,观察速度值的变化(Expect value: speed = 50

    pid_speed.Kp = 7.0;
    pid_speed.Ki = 20.0;
    pid_speed.Kd = 14.0;

串口log如下,在5s左右就完成速度定速功能

5.2 测试案例2

PID参数设置如下类型,观察速度值的变化(Expect value: speed = 50

    pid_speed.Kp = 7.0;
    pid_speed.Ki = 2.0;
    pid_speed.Kd = 4.0;

串口log如下,在2min左右才完成速度定速功能

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/683247.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java中常用的单目运算符及用法详解

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。运营社区&#xff1a;C站/掘金/腾讯云&#xff1b;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一…

2024年清洁能源与可持续发展国际会议(ICDESMF 2024)

2024 International Conference on Clean Energy and Sustainable Development 【1】大会信息 会议简称&#xff1a;ICDESMF 2024 大会时间&#xff1a;2024-07-22 大会地点&#xff1a;中国大理 截稿时间&#xff1a;2024-07-08(以官网为准&#xff09; 审稿通知&#xff1a…

JFinal学习06 控制器——getPara()接收数据

JFinal学习06 控制器——getPara()接收数据 视频来源https://www.bilibili.com/video/BV1Bt411H7J9/?spm_id_from333.337.search-card.all.click 文章目录 JFinal学习06 控制器——getPara()接收数据零、JFinal数据提交的三种方式一、get提交二、post提交三、url参数化提交四、…

【全开源】Shopro社区团购(小程序版)

邻里间的购物新选择 基于Fastadmin后端管理系统Uniapp客户端&#xff08;仅支持微信小程序&#xff09;开发&#xff0c;生鲜果蔬社区团购的不二之选、快速搭建社区团购平台、让你的产品走进上千个社区。线上团购线下自提&#xff0c;玩转社区消费新模式提供专业、优质的社区团…

计算机网络 期末复习(谢希仁版本)第5章

**屏蔽作用&#xff1a;**运输层向高层用户屏蔽了下面网络核心的细节&#xff08;如网络拓扑、所采用的路由选择协议等&#xff09;&#xff0c;使应用进程看见的就是好像在两个运输层实体之间有一条端到端的逻辑通信信道。 10. 端口用一个 16 位端口号进行标志&#xff0c;允许…

Linux—小小内核升级

本篇主要是讲述下关于内核的一些基本常识&#xff0c;并记录下内核升级和编译的过程&#xff0c;若有遗漏/有误之处&#xff0c;望各位大佬们指出。 Ⅰ 基本内核常识 常见内核安装包 内核(kernel)&#xff1a;这是Linux操作系统的核心部分&#xff0c;它负责管理系统的硬件和…

信号(上)

本节目标&#xff1a; 1. 掌握Linux信号的基本概念 2. 掌握信号产生的一般方式 3. 理解信号递达和阻塞的概念&#xff0c;原理。 4. 掌握信号捕捉的一般方式。 5. 重新了解可重入函数的概念。 6. 了解竞态条件的情景和处理方式 7. 了解SIGCHLD信号&#xff0c; 重新编写信号处理…

实现k8s网络互通

前言 不管是docker还是k8s都会在物理机组件虚拟局域网&#xff0c;只不过是它们实现的目标不同。 docker&#xff1a;针对同一个物理机&#xff08;宿主机&#xff09; k8s&#xff1a;针对的是多台物理机&#xff08;宿主机&#xff09; Docker 虚拟局域网 K8S虚拟局域网 …

2024-06-05-记一次cnvd渗透

前言&#xff1a;挖src挖郁闷了&#xff0c;闲来无事选择挖一个cnvd来练练手&#xff0c;本次的漏洞都没啥难度&#xff0c;企查查资产过了5000万 说一下cnvd证书的下放标准 对于中危及中危以上通用型漏洞&#xff08;CVSS2.0基准评分超过4.0分&#xff09;&#xff0c;以及涉…

Wireshark抓包工具使用 项目实战

Wireshark 是一个开源的网络协议分析器&#xff0c;它可以让你捕获和分析网络数据包&#xff0c;帮助你诊断网络问题、监控网络流量、分析协议和进行安全审计。以下是一些基本的 Wireshark 用法&#xff1a; 捕获数据包&#xff1a; 打开 Wireshark&#xff0c;选择要捕获数据包…

13- Redis 中的 压缩列表 数据结构

压缩列表的最大特点&#xff0c;就是它被设计成一种内存紧凑型的数据结构&#xff0c;占用 一块连续的内存空间&#xff0c;不仅可以利用 CPU 缓存&#xff0c;而且会针对不同长度的数据&#xff0c;进行相应编码&#xff0c;这种方法可以有效的节省内存开销。 但是&#xff0…

C#-foreach循环语句

foreach循环语句 语法&#xff1a; foreach(数据类型 变量名 in 数组或集合对象) { 语句块; } foreach 会在每次循环的过程中&#xff0c;依次从数组或集合对象中取出一个新的元素放foreach( )里定义的变量中&#xff0c;直到所有元素都成功取出后退出循环。 foreach循环…

Mysql root用户远程连接失败解决方案

最近&#xff0c;踩坑云服务器通过root用户远程连接Mysql数据库失败&#xff0c;Mysql 版本为 5.7.44&#xff0c;原因如下&#xff0c;因为root用户权限过大&#xff0c;可能会有风险操作&#xff0c;可以新增其他用户来解决此问题&#xff0c;如果一定要用root用户&#xff0…

C# Onnx E2Pose人体关键点检测

C# Onnx E2Pose人体关键点检测 目录 效果 模型信息 项目 代码 下载 效果 模型信息 Inputs ------------------------- name&#xff1a;inputimg tensor&#xff1a;Float[1, 3, 512, 512] --------------------------------------------------------------- Outputs ---…

【python010】获取任意多边形区域内的经纬度点并可视化

1.熟悉、梳理、总结项目研发实战中的Python开发日常使用中的问题、知识点等&#xff0c;如获取任意多边形区域内的经纬度点并可视化&#xff0c;找了N篇文章没发现有效的解决方案。 2.欢迎点赞、关注、批评、指正&#xff0c;互三走起来&#xff0c;小手动起来&#xff01; 3.欢…

Leetcode刷题(四十)

Pow(x, n)&#xff08;Medium&#xff09; 实现 pow(x, n) &#xff0c;即计算 x 的整数 n 次幂函数&#xff08;即&#xff0c;xn &#xff09;。示例 1&#xff1a;输入&#xff1a;x 2.00000, n 10 输出&#xff1a;1024.00000 示例 2&#xff1a;输入&#xff1a;x 2.1…

微服务Day7学习-数据聚合、同步、补全

文章目录 数据聚合聚合分类 自动补全DSL实现Bucket聚合DSL实现Metrics聚合RestAPI实现聚合多条件聚合对接前端接口拼音分词器自定义分词器自动补全查询实现酒店搜索框自动补全 数据同步数据同步思路分析利用mq实现mysql与elasticsearch数据同步 集群介绍搭建ES集群 数据聚合 聚…

电拖基础JIAOXUE

1.最简单的TT马达&#xff0c;实际就是一个减速电机&#xff1a; 减速箱的内部包含了一组齿轮。在实际的使用中&#xff0c;绝大部分的电动机都要和减速箱配合使用&#xff0c;因为一般的电机转速都在每分钟几千转甚至1万转以上&#xff0c;而在实际的使用中并不需要这么快的转…

RN:Error: /xxx/android/gradlew exited with non-zero code: 1

问题 执行 yarn android 报错&#xff1a; 解决 这个大概率是缓存问题&#xff0c;我说一下我的解决思路 1、yarn doctor 2、根据黄色字体提示&#xff0c;说我包版本不对&#xff08;但是这个是警告应该没事&#xff0c;但是我还是装了&#xff09; npx expo install --…

Lodop 实现局域网打印

文章目录 前言一、Lodop支持打印的方式lodop 打印方式一般有3种&#xff1a;本地打印局域网集中打印广域网AO打印 二、集成步骤查看lodop 插件的服务端口&#xff1a;查看ip后端提供接口返回ip&#xff0c;前端动态获取最后步骤 前言 有时候会根据不同的ip来获取资源文件&…