[STM32+HAL]DengFOC移植之闭环速度控制

一、前言:

有关闭环位置控制,详见[STM32+HAL]DengFOC移植之闭环位置控制

二、Keil填写代码:

1、AS5600读取角位移
#include "AS5600.h"
#include "math.h"
#include "FOC2.h"float angle_prev=0; 							// 最后一次调用 getSensorAngle() 的输出结果,用于得到完整的圈数和速度
long angle_prev_ts=0; 							// 上次调用 getAngle 的时间戳
float vel_angle_prev=0; 						// 最后一次调用 getVelocity 时的角度
long vel_angle_prev_ts=0; 						// 最后速度计算时间戳
int32_t full_rotations=0; 						// 总圈数计数
int32_t vel_full_rotations=0;			 		// 用于速度计算的先前完整旋转圈数/* IIC读多字节 */
void AS5600_Read_Reg(uint16_t reg, uint8_t* buf, uint8_t len)
{HAL_I2C_Mem_Read(&hi2c1, AS5600_ADDRESS, reg, I2C_MEMADD_SIZE_8BIT, buf, len, 100);
}/* 得到弧度制的角度,范围在0-6.28 */
float GetAngle_Without_Track(void)
{float angle_d;									// GetAngle_Without_Track()的返回值int16_t in_angle;uint8_t temp[DATA_SIZE]={0};AS5600_Read_Reg( Angle_Hight_Register_Addr, temp, DATA_SIZE);in_angle = ((int16_t)temp[0] <<8) | (temp[1]);angle_d = (float)in_angle * (2.0f*PI) / 4096;//angle_d为弧度制,范围在0-6.28return angle_d;
}/* 得到弧度制的带圈数角度 */
float GetAngle(void)
{float angle_cd;									// GetAngle()的返回值float val = GetAngle_Without_Track();float d_angle = val - angle_prev;//计算旋转的总圈数//通过判断角度变化是否大于80%的一圈(0.8f*6.28318530718f)来判断是否发生了溢出,如果发生了,则将full_rotations增加1(如果d_angle小于0)或减少1(如果d_angle大于0)。if(fabs(d_angle) > (0.8f*2.0f*PI) ) full_rotations += ( d_angle > 0 ) ? -1 : 1;angle_prev = val;angle_cd = full_rotations * (2.0f*PI) + angle_prev;return angle_cd;
}/* 初始化AS5600 */
void AS5600_Init(void) {vel_angle_prev = GetAngle_Without_Track();vel_angle_prev_ts = micros();HAL_Delay(1);GetAngle_Without_Track();angle_prev = GetAngle_Without_Track();angle_prev_ts = micros();
}/* 更新当前角度值 */
void AS5600_Update(void) {float val = GetAngle_Without_Track();angle_prev_ts = micros();float d_angle = val - angle_prev;	//前一次循环的角度-当前的角度// 圈数检测if(fabs(d_angle) > (0.8f*_2PI) ) full_rotations += ( d_angle > 0 ) ? -1 : 1;  //判断是否大于80%的360度;判断转向angle_prev = val;
}/* 上一次的度数 */
float AS5600_GetMechanicalAngle(void) {return angle_prev;
}/*角度输出函数圈数转化为角度的弧度值,再加上未转满一圈的度数
*/
float AS5600_GetAngle(void){printf("%.2f\r\n",(float)full_rotations * _2PI + angle_prev);return (float)full_rotations * _2PI + angle_prev;
}/* 获取编码器速度 */
float AS5600_GetVelocity(void) {// 计算采样时间float Ts = (angle_prev_ts - vel_angle_prev_ts)*1e-6;// 快速修复奇怪的情况(微溢出)if(Ts <= 0) Ts = 1e-3f;// 速度计算float vel = ( (float)(full_rotations - vel_full_rotations)*_2PI + (angle_prev - vel_angle_prev) ) / Ts;// 保存变量以待将来使用vel_angle_prev = angle_prev;vel_full_rotations = full_rotations;vel_angle_prev_ts = angle_prev_ts;printf("%.2f\r\n",vel);return vel;
}

2、pid.c
#include "pid.h"
#include "FOC2.h"void PIDController_Init(PIDController* pid, float P, float I, float D, float ramp, float limit)
{pid->P = P;pid->I = I;pid->D = D;pid->output_ramp = ramp;		// PID控制器加速度限幅pid->limit = limit;	 			// PID控制器输出限幅pid->error_prev = 0.0f;pid->output_prev = 0.0f;pid->integral_prev = 0.0f;pid->timestamp_prev = micros(); // 假设时间戳以某种形式初始化
}/* PID控制器函数输入结构体及偏差值,输出相应的电压  */
float PIDController_Operator(PIDController* pid, float error)
{// 计算两次循环中间的间隔时间unsigned long timestamp_now = micros();float Ts = (timestamp_now - pid->timestamp_prev) * 1e-6f;if(Ts <= 0 || Ts > 0.5f) Ts = 1e-3f;// P环float proportional = pid->P * error;// Tustin 散点积分(I环)float integral = pid->integral_prev + pid->I*Ts*0.5f*(error + pid->error_prev);integral = _constrain(integral, -pid->limit, pid->limit);// D环(微分环节)float derivative = pid->D*(error - pid->error_prev)/Ts;// 将P,I,D三环的计算值加起来float output = proportional + integral + derivative;output = _constrain(output, -pid->limit, pid->limit);if(pid->output_ramp > 0){// 对PID的变化速率进行限制float output_rate = (output - pid->output_prev)/Ts;if (output_rate > pid->output_ramp)output = pid->output_prev + pid->output_ramp*Ts;else if (output_rate < - pid->output_ramp)output = pid->output_prev - pid->output_ramp*Ts;}// 保存值(为了下一次循环)pid->integral_prev = integral;pid->output_prev = output;pid->error_prev = error;pid->timestamp_prev = timestamp_now;return output;
}/*
// 使用示例
int main() {PIDController pid;PIDController_Init(&pid, 1.0f, 0.0f, 0.0f, 0.1f, 100.0f);float output = PIDController_Update(&pid, 0.5f);printf("PID output: %f\n", output);return 0;
}
*/
3、简易低通滤波
#include "lowpass_filter.h"
#include <stdint.h>void LowPassFilter_Init(LowPassFilter *filter, float time_constant) {filter->Tf = time_constant;filter->y_prev = 0.0f;filter->timestamp_prev = micros();
}float LowPassFilter_process(LowPassFilter *filter, float x) {unsigned long timestamp = micros();float dt = (float)(timestamp - filter->timestamp_prev) * 1e-6f;			//计算两次循环的时间间隔并转换为秒if (dt < 0.0f) dt = 1e-3f;												//处理因为micros跳变引起的时间间隔跳变else if (dt > 0.3f) {													//处理时间间隔大于0.3s的情况filter->y_prev = x;filter->timestamp_prev = timestamp;return x;}float alpha = filter->Tf / (filter->Tf + dt);float y = alpha * filter->y_prev + (1.0f - alpha) * x;filter->y_prev = y;filter->timestamp_prev = timestamp;return y;
}

4、main.c
/* USER CODE BEGIN PV */
float motor_target=2;    //目标速度
float angle_target=2;    //目标角度
extern int PP,DIR;
/* USER CODE END PV */  /* USER CODE BEGIN 2 */printf("Hello World\r\n");HAL_Delay(500);DFOC_Vbus(12.6);			// 输入电压12.6VDFOC_alignSensor(PP,DIR);	// 设置转轴数和方向HAL_Delay(100);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){DFOC_M0_set_Force_Angle(angle_target);	//设置位置
//	  DFOC_M0_SetVelocity(motor_target);		//设置速度/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

I2C协议介绍

I2C&#xff08;Inter-Integrated Circuit&#xff09;协议是一种广泛使用的串行通信协议&#xff0c;它允许多个设备通过两根线路进行通信。这种协议最初由Philips Semiconductor&#xff08;现在的NXP Semiconductors&#xff09;在1980年代推出&#xff0c;目的是简化集成电…

2024泰迪杯c题详细思路代码讲解:竞赛论文的辅助自动评阅

C&#xff1a;竞赛论文的辅助自动评阅 步骤一&#xff1a;理解拆解题目&#xff0c;并对附件1中的论文集进行初步分析。 步骤二&#xff1a;特征构造 论文完整性&#xff1a;开发算法以检查论文是否全面回答了赛题。这包括自然语言处理(NLP)技术来识别关键段落和论证的完整…

如何使用vscode启动Flask并实现无公网IP远程访问内网服务

文章目录 1. 安装部署Flask2. 安装Cpolar内网穿透3. 配置Flask的web界面公网访问地址4. 公网远程访问Flask的web界面 本篇文章主要讲解如何在本地安装Flask&#xff0c;以及如何将其web界面发布到公网进行远程访问。 Flask是目前十分流行的web框架&#xff0c;采用Python编程语…

LeetCode初级算法书Java题解日常更新

LeetCode初级算法高效题解&#xff08;含思路注释&#xff09; 文章目录 LeetCode初级算法高效题解&#xff08;含思路注释&#xff09;前言一、数组1.删除排序数组中的重复项2.买卖股票的最佳时机 II3.旋转数组4.存在重复元素 总结 前言 决定用四个月过一下算法 一、数组 1.…

【绩效管理】帮助零售企业建立分层分类绩效考核体系项目纪实

购物中心张经理评价&#xff1a;“员工的绩效管理一直是困扰我公司的难题&#xff0c;我们只懂得怎么经营&#xff0c;至于怎么做人力资源管理&#xff0c;真是一点都不懂。这次华恒智信为我们提供的服务对我们的帮助很大。基于企业实际调研情况&#xff0c;华恒智信专家明确指…

Linux-等待子进程

参考资料&#xff1a;《Linux环境编程&#xff1a;从应用到内核》 僵尸进程 进程退出时会进行内核清理&#xff0c;基本就是释放进程所有的资源&#xff0c;这些资源包括内存资源、文件资源、信号量资源、共享内存资源&#xff0c;或者引用计数减一&#xff0c;或者彻底释放。…

PANet网络

PANet&#xff08;Path Aggregation Network&#xff09;是一种用于语义分割任务的神经网络结构&#xff0c;旨在解决多尺度特征融合的问题。该网络结构由中国科学院计算技术研究所提出&#xff0c;在2018年的论文中首次提出。 PANet的主要目标是解决语义分割任务中多尺度信息…

电脑开机启动项设置

电脑开机启动项设置 一、Windows 系统&#xff1a; 1、Windows 系统&#xff0c;可以通过【系统配置实用程序】来设置开机启动项&#xff1a; 1&#xff09;、按【WinR】组合键&#xff0c;打开【运行】对话框。 2&#xff09;、输入【msconfig】&#xff0c;点击【确定】或…

Transformer 模型及其典型应用研究

摘要&#xff1a; Transformer 模型是一种基于自注意力机制的深度学习架构&#xff0c;在自然语言处理等领域取得了巨大成功。本文介绍了 Transformer 模型的原理和结构&#xff0c;并探讨了其在语言翻译、文本生成、对话系统、语言模型、图像处理和推荐系统等典型应用领域的研…

Java中的Stream流常用接口和方法

​TOC 第一章&#xff1a;Stream流是什么 1.1&#xff09;简单介绍 学习Stream流就绕不开Lambda表达式&#xff0c; 需要了解Lambda表达式可以看一下这篇–>&#xff1a;Lambda表达式学习 1.其实“流”是个抽象概念&#xff0c;我们把现实世界中与Stream流有相同特性的…

一条SQL查询语句的执行顺序

SQL常用字段书写顺序 SELECT&#xff1a;选择要查询的列。 FROM&#xff1a;指定数据来源&#xff0c;即表名。 JOIN&#xff1a;根据指定的连接条件将多个表连接在一起。 ON&#xff1a;指定连接条件&#xff0c;即哪些列的值匹配时&#xff0c;应该将两个表中的行组合在一起。…

目标 url 存在 host 头攻击漏洞

安全问题九: 目标 url 存在 host 头攻击漏洞 解决方案: 方法-: 修改 nginx.conf 添加一个默认server,当host头被修改匹配不到server时会跳到该默认server 该默认 server 直接返回 403 错误。 例子如下: server { listen 8888 default; server name ; location /{ return 403; }…

【Angular】什么是Angular中的APP_BASE_HREF

1 概述: 在这篇文章中&#xff0c;我们将看到Angular 10中的APP_BASE_HREF是什么以及如何使用它。 APP_BASE_HREF为当前页面的基础href返回一个预定义的DI标记。 APP_BASE_HREF是应该被保留的URL前缀。 2 语法: provide: APP_BASE_HREF, useValue: /gfgapp3 步骤: 在app.m…

SAP ERP 公有云有哪些模块?

随着全球化竞争的加剧和企业管理需求的日益复杂化&#xff0c;越来越多的企业开始采用云端企业资源计划&#xff08;ERP&#xff09;系统来优化业务流程。SAP ERP 公有云&#xff08;SAP S/4HANA Cloud, public edition&#xff09;作为一款领先的云端ERP解决方案&#xff0c;为…

不要再使用 @Builder 注解了!有深坑呀!

曾经&#xff0c;我在《千万不要再随便使用 lombok 的 Builder 了&#xff01;》 一文中提到 Builder 注解的其中一个大坑会导致默认值失效&#xff01; 最近阅读了 《Oh !! Stop using Builder》 发现 Builder 的问题还不止一个&#xff0c;Builder 会让人误以为是遵循构建器…

掌握Linux虚拟网络设备:从基础到应用的全面指南

在现代计算环境中&#xff0c;尤其是云计算☁️、容器化&#x1f4e6;和微服务架构&#x1f3d7;️大行其道的时代&#xff0c;了解和掌握Linux虚拟网络设备变得极为重要。本文将深入探讨Linux虚拟网络设备的世界&#xff0c;带你了解它们是什么、包含哪些类型、为什么需要它们…

LeetCode热题Hot100 - 电话号码的字母组合

一刷~ 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 思路&#xff1a; 首先&#xff0c;需要数字到字母表的映射&#xf…

揭秘淘宝商品详情数据接口(Taobao.item_get)

淘宝商品详情数据接口&#xff08;Taobao.item_get&#xff09;是一种允许开发者通过API访问淘宝平台上的商品详情信息的接口。通过该接口&#xff0c;开发者可以获取到商品的标题、价格、销量、描述等详细信息&#xff0c;为商品展示和销售提供数据支持。 请求示例&#xff0…

K8s学习八(配置与存储_配置)

配置与存储 配置管理 ConfigMap ConfigMap的创建 一般用于去存储 Pod 中应用所需的一些配置信息&#xff0c;或者环境变量&#xff0c;将配置于 Pod 分开&#xff0c;避免应为修改配置导致还需要重新构建 镜像与容器。configmap缩写为cmkubectl create cm -h来查看创建命令…

#Java# ATM机系统(登录账号和退出账号大体结构和想法)

1.功能分析&#xff08;登录页面还未完善&#xff0c;所以这里只是简写&#xff09; landAccount()方法&#xff0c;登录账户&#xff1a; 从保存用户信息的文件中查找是否存在该账户&#xff0c;如果不存在则提示”该用户不存在“&#xff0c;如果存在则对用户输入的密码和该…