当前位置: 首页 > news >正文

24年电赛——自动行驶小车(H题)MSPM0G3507-编码电机驱动与通用PID

一、编码电机驱动

        编码电机的详情可以查看此篇文章:

stm32平衡小车--(1)JGB-520减速电机+tb6612(附测试代码)_jgb520-CSDN博客

        简单来说,编码电机的驱动主要是给一个 PWM 和一个正负级就能驱动。PWM 的大小决定转速快慢,电机的两个电源正负极不同决定了旋转的方向不同。

1、PWM设置:

        PWM 的值可以在图形化配置界面进行配置,同时也可以通过如下函数进行设置:第一个参数是定时器,第二个是捕获比较值,第三个是通道。

void DL_Timer_setCaptureCompareValue(GPTIMER_Regs *gptimer, uint32_t value, DL_TIMER_CC_INDEX ccIndex);

        如下是设置占空比的一个函数。第一个参数是捕获比较值,第二个参数是设置通道,我是用一个定时器输出两路 PWM,所以需要两个通道。因为设置的是下降沿触发,系统主频是80MHz,进行了10000分频,所以计数值就是8000。duty = 7999 - 7999 * (duty/3200.0);就可以将捕获比较值从8000映射到3200。然后下面 if 来判断设置PWM输出的通道。

// 设置电机PWM占空比,取值范围为3200~0,对应占空比为100%~0%
void Motor_SetPwm(float duty,uint8_t channel) {duty = 7999 - 7999 * (duty/3200.0);if(channel==0){DL_TimerA_setCaptureCompareValue(PWM_MOTOR_INST , duty, DL_TIMER_CC_0_INDEX );  // 设置定时器捕获比较值}else {DL_TimerA_setCaptureCompareValue(PWM_MOTOR_INST , duty, DL_TIMER_CC_1_INDEX );  // 设置定时器捕获比较值}
}

        PWM 图形化配置:

 2、电机方向设置

        此函数与上面的参数一致。这两个函数分别用来设置引脚低电平和高电平。

DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL1_PORT, GPIO_MOTOR_PIN_FL1_PIN);
DL_GPIO_setPins(GPIO_MOTOR_PIN_FL2_PORT, GPIO_MOTOR_PIN_FL2_PIN);

        下面函数时根据驱动电机。duty 值为正,电机正转,duty 值为负,电机反转;channel 值为0,驱动右轮,channel 值为1,驱动左轮。

// 电机前进控制函数
void Set_Speed(float duty, uint8_t channel) {if(channel==0){     //判断左右轮if(duty>0){     //判断正反转Motor_SetPwm(duty,channel);DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL1_PORT, GPIO_MOTOR_PIN_FL1_PIN);DL_GPIO_setPins(GPIO_MOTOR_PIN_FL2_PORT, GPIO_MOTOR_PIN_FL2_PIN);}else if(duty<0){Motor_SetPwm(-duty,channel);DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL2_PORT, GPIO_MOTOR_PIN_FL2_PIN);DL_GPIO_setPins(GPIO_MOTOR_PIN_FL1_PORT, GPIO_MOTOR_PIN_FL1_PIN);}else {DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL1_PORT, GPIO_MOTOR_PIN_FL1_PIN);DL_GPIO_clearPins(GPIO_MOTOR_PIN_FL2_PORT, GPIO_MOTOR_PIN_FL2_PIN);}}else {if(duty>0){Motor_SetPwm(duty,channel);DL_GPIO_clearPins(GPIO_MOTOR_PIN_FR1_PORT, GPIO_MOTOR_PIN_FR1_PIN);DL_GPIO_setPins(GPIO_MOTOR_PIN_FR2_PORT, GPIO_MOTOR_PIN_FR2_PIN);}else if(duty<0){Motor_SetPwm(-duty,channel);DL_GPIO_clearPins(GPIO_MOTOR_PIN_FR2_PORT, GPIO_MOTOR_PIN_FR2_PIN);DL_GPIO_setPins(GPIO_MOTOR_PIN_FR1_PORT, GPIO_MOTOR_PIN_FR1_PIN);}else {DL_GPIO_clearPins(GPIO_MOTOR_PIN_FR1_PORT, GPIO_MOTOR_PIN_FR1_PIN);DL_GPIO_clearPins(GPIO_MOTOR_PIN_FR2_PORT, GPIO_MOTOR_PIN_FR2_PIN);}}
}

二、通用PID

        其中增量式 PID 不需要初始阈值,其输出主要是与上次误差与上上次误差有关,适合调节稳定速度;

        位置式 PID 需要初始阈值,其输出的结果与历史的状态有关,适合将速度维持在某个定值。

pid.c

#include "pid.h"
#include <math.h>// 初始化PID结构体
void PID_Init(PID *s_PID, PID_VAR_TYPE set_point, PID_VAR_TYPE Proportion,PID_VAR_TYPE Integral, PID_VAR_TYPE Derivative)
{// 初始化PID参数s_PID->SetPoint = set_point;            // 设定目标值s_PID->Proportion = Proportion;         // 比例系数s_PID->Integral = Integral;             // 积分系数s_PID->Derivative = Derivative;         // 微分系数s_PID->Error = 0;                       // 当前误差s_PID->LastError = 0;                   // 上一次误差s_PID->PrevError = 0;                   // 上上次误差s_PID->SumError = 0;                    // 总误差s_PID->LastResult = 0;                  // 上一次计算结果s_PID->Result = 0;                      // 当前计算结果s_PID->OutMax = DEFAULT_PID_OUT_MAX;    // 输出上限s_PID->OutMin = DEFAULT_PID_OUT_MIN;    // 输出下限s_PID->IntegralMax = DEFAULT_PID_INTEGRAL_OUT_MAX;  // 积分输出上限s_PID->IntegralMin = DEFAULT_PID_INTEGRAL_OUT_MIN;  // 积分输出下限
}// 设置PID的目标值
void PID_SetPoint(PID *s_PID, PID_VAR_TYPE set_point)
{s_PID->SetPoint = set_point;
}// 设置PID的输出范围
void PID_SetOutRange(PID *s_PID, PID_VAR_TYPE outMax, PID_VAR_TYPE outMin)
{s_PID->OutMax = outMax;s_PID->OutMin = outMin;
}// 设置PID的积分输出范围
void PID_SetIntegralOutRange(PID *s_PID, PID_VAR_TYPE outMax, PID_VAR_TYPE outMin)
{s_PID->IntegralMax = outMax;s_PID->IntegralMin = outMin;
}// 增量型PID计算
PID_VAR_TYPE Increment_PID_Cal(PID *s_PID, PID_VAR_TYPE now_point)
{s_PID->LastResult = s_PID->Result;   // 保存上一次的计算结果// 计算误差s_PID->Error = s_PID->SetPoint - now_point;// PID计算s_PID->Result =s_PID->LastResult +s_PID->Proportion * (s_PID->Error - s_PID->LastError) +  // 比例项s_PID->Integral * s_PID->Error +                          // 积分项s_PID->Derivative * (s_PID->Error - 2 * s_PID->LastError + s_PID->PrevError);  // 微分项s_PID->PrevError = s_PID->LastError;   // 更新上上次误差s_PID->LastError = s_PID->Error;       // 更新上一次误差// 限制输出范围if (s_PID->Result > s_PID->OutMax)s_PID->Result = s_PID->OutMax;else if (s_PID->Result < s_PID->OutMin)s_PID->Result = s_PID->OutMin;return s_PID->Result;
}// 位置型PID计算
PID_VAR_TYPE Position_PID_Cal(PID *s_PID, PID_VAR_TYPE now_point)
{s_PID->LastResult = s_PID->Result;   // 保存上一次的计算结果// 计算误差s_PID->Error = s_PID->SetPoint - now_point;s_PID->SumError += s_PID->Error;    // 更新总误差// 限制积分输出范围PID_VAR_TYPE IOutValue = s_PID->SumError * s_PID->Integral;if (IOutValue > s_PID->IntegralMax)IOutValue = s_PID->IntegralMax;else if (IOutValue < s_PID->IntegralMin)IOutValue = s_PID->IntegralMin;// PID计算s_PID->Result =s_PID->Proportion * s_PID->Error +      // 比例项IOutValue +                            // 积分项s_PID->Derivative * (s_PID->Error - s_PID->LastError);  // 微分项s_PID->PrevError = s_PID->LastError;   // 更新上上次误差s_PID->LastError = s_PID->Error;       // 更新上一次误差// 限制输出范围if (s_PID->Result > s_PID->OutMax)s_PID->Result = s_PID->OutMax;else if (s_PID->Result < s_PID->OutMin)s_PID->Result = s_PID->OutMin;return s_PID->Result;
}// 综合型PID计算
PID_VAR_TYPE PID_Cal(PID *s_PID, PID_VAR_TYPE now_point)
{s_PID->LastResult = s_PID->Result;   // 保存上一次的计算结果// 计算误差s_PID->Error = s_PID->SetPoint - now_point;s_PID->SumError += s_PID->Error;    // 更新总误差// 限制积分输出范围PID_VAR_TYPE IOutValue = s_PID->SumError * s_PID->Integral;if (IOutValue > s_PID->IntegralMax)IOutValue = s_PID->IntegralMax;else if (IOutValue < s_PID->IntegralMin)IOutValue = s_PID->IntegralMin;// PID计算s_PID->Result =s_PID->Proportion * (s_PID->Error + IOutValue) +   // 比例项s_PID->Derivative * (s_PID->Error - s_PID->LastError);  // 微分项s_PID->PrevError = s_PID->LastError;   // 更新上上次误差s_PID->LastError = s_PID->Error;       // 更新上一次误差// 限制输出范围if (s_PID->Result > s_PID->OutMax)s_PID->Result = s_PID->OutMax;else if (s_PID->Result < s_PID->OutMin)s_PID->Result = s_PID->OutMin;return s_PID->Result;
}

pid.h

#ifndef __PID_H
#define __PID_H	  //PID输出范围宏定义
#define DEFAULT_PID_OUT_MAX               ( 3200)
#define DEFAULT_PID_OUT_MIN               (-3200)
//PID积分范围宏定义
#define DEFAULT_PID_INTEGRAL_OUT_MAX      ( 400)
#define DEFAULT_PID_INTEGRAL_OUT_MIN      (-400)//PID变量类型宏定义
#define PID_VAR_TYPE                            float     //int//定义结构体
typedef struct
{PID_VAR_TYPE SetPoint;      // 设定目标 PID_VAR_TYPE Proportion;    // 比例常数PID_VAR_TYPE Integral;      // 积分常数PID_VAR_TYPE Derivative;    // 微分常数 PID_VAR_TYPE SumError;      // 积分和PID_VAR_TYPE Error;         // 误差PID_VAR_TYPE LastError;     // 上次误差 PID_VAR_TYPE PrevError;     // 前一次误差   PID_VAR_TYPE LastResult;    // 上次计算结果PID_VAR_TYPE Result;        // 当前计算结果PID_VAR_TYPE OutMax;        // 输出限幅最大值PID_VAR_TYPE OutMin;        // 输出限幅最小值PID_VAR_TYPE IntegralMax;   // 积分限幅最大值PID_VAR_TYPE IntegralMin;   // 积分限幅最小值
} PID;extern void PID_Init(PID *s_PID, PID_VAR_TYPE set_point,PID_VAR_TYPE Proportion,PID_VAR_TYPE Integral,PID_VAR_TYPE Derivative);  //PID初始化extern void PID_SetOutRange(PID *s_PID, PID_VAR_TYPE outMax, PID_VAR_TYPE outMin);          //设置PID输出范围
extern void PID_SetIntegralOutRange(PID *s_PID, PID_VAR_TYPE outMax, PID_VAR_TYPE outMin);  //设置PID积分范围
extern void PID_SetPoint(PID *s_PID, PID_VAR_TYPE set_point);                               //设置目标值extern PID_VAR_TYPE Increment_PID_Cal(PID *s_PID, PID_VAR_TYPE now_point);  //增量式PID计算
extern PID_VAR_TYPE Position_PID_Cal(PID *s_PID, PID_VAR_TYPE now_point);   //位置式PID计算
extern PID_VAR_TYPE PID_Cal(PID *s_PID, PID_VAR_TYPE now_point);            //比例外置式PID#endif 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • unity 小怪播放动画导致ui抖动
  • C-V2X通信协议
  • 正点原子imx6ull-mini-Linux驱动之Linux LCD 驱动实验(19)
  • 【数据泄露】最新 FBI 官员数据库泄露事件
  • createObjectURL的部分使用讲解
  • 锅总浅析防火墙
  • 三线程分别打印1、2、3顺序执行10次
  • 游戏加速器推荐 网游加速器排行榜
  • 快速将网站从HTTP升级为HTTPS
  • Git代码冲突怎么处理?
  • gptpdf深度解析:开源文档处理技术全攻略
  • AI人工智能分析王楚钦球拍被踩事件的真相
  • [Day 43] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
  • Linux:Xshell相关配置及前期准备
  • python-素数回文数的个数(赛氪OJ)
  • @angular/forms 源码解析之双向绑定
  • [NodeJS] 关于Buffer
  • Brief introduction of how to 'Call, Apply and Bind'
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • echarts花样作死的坑
  • fetch 从初识到应用
  • Gradle 5.0 正式版发布
  • java B2B2C 源码多租户电子商城系统-Kafka基本使用介绍
  • Java,console输出实时的转向GUI textbox
  • laravel with 查询列表限制条数
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 关于 Cirru Editor 存储格式
  • 入职第二天:使用koa搭建node server是种怎样的体验
  • 实现简单的正则表达式引擎
  • 为物联网而生:高性能时间序列数据库HiTSDB商业化首发!
  • ​数据链路层——流量控制可靠传输机制 ​
  • ## 基础知识
  • (附源码)ssm码农论坛 毕业设计 231126
  • (黑客游戏)HackTheGame1.21 过关攻略
  • (回溯) LeetCode 77. 组合
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • (切换多语言)vantUI+vue-i18n进行国际化配置及新增没有的语言包
  • (四)js前端开发中设计模式之工厂方法模式
  • (提供数据集下载)基于大语言模型LangChain与ChatGLM3-6B本地知识库调优:数据集优化、参数调整、Prompt提示词优化实战
  • (原创)Stanford Machine Learning (by Andrew NG) --- (week 9) Anomaly DetectionRecommender Systems...
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (转)ObjectiveC 深浅拷贝学习
  • .bat批处理(一):@echo off
  • .NET CF命令行调试器MDbg入门(一)
  • .NET Core/Framework 创建委托以大幅度提高反射调用的性能
  • .net 程序 换成 java,NET程序员如何转行为J2EE之java基础上(9)
  • .Net 转战 Android 4.4 日常笔记(4)--按钮事件和国际化
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)
  • .NET单元测试
  • .net连接oracle数据库
  • .NET中的Exception处理(C#)
  • .sh文件怎么运行_创建优化的Go镜像文件以及踩过的坑
  • @DependsOn:解析 Spring 中的依赖关系之艺术
  • [000-01-022].第06节:RabbitMQ中的交换机介绍