旋钮键盘项目---foc讲解(开环)

这里就不过多的讲解什么原理,公式的变换了,感兴趣的可以看灯哥开源,讲解的非常好的。当然,更细致的讲解,也可以看b站其他教学。

我这里主要讲解我对于开环部分的理解,以及stm32代码的实现逻辑。可以看作是讲解灯哥的代码流程,毕竟是一致的。

本次stm32使用hal库开发。

一、为什么会有克拉克变换、帕克变换

一个电机,我们如果想要它能够在损失最小的情况下运动,那么就是我们希望力永远垂直鱼当前指向的方向。(这里,我们把电机看作一个指针,电机转动,其实就是指针转动。想要指针损失最小转动,自然力就是垂直与指针,否则就会有损耗,高中物理嘛)。那么问题来,我们知道需要力,我们该如何设定电机输入的uwv电压,来设定这个力呢?

我们可以将力分解,分解为一个固定坐标系下的两个方向的力。一般是x,y轴的方向。为什么呢?当然是好算,很多的表达式都可以不要再去计算偏移角度了。当然,这里就出现了一个问题,这个力是不断变化的,我们怎么分解?你这个力现在指向左侧,一会又指向左下角了,怎么做分解呢?所有这个当前的角度,我们是必须知道的。有了角度才好分解。ok,这个角度,我们可以使用传感器来获取。这个变换也就是帕克逆变换!

好了,我们现在就当我们得到水平固定坐标系下的两个分解,那么如何得到uwv呢?这个很简单了,我们直接将u或者其他,无所谓哪一个当作x轴,这样就不需要算它了。x轴分解得到多大,就是它的值。借用灯哥的图,这里的la=lα,非常简便,减少了计算。(所以其实不是一定要这样的,你可以根据自己喜爱去偏转,只是麻烦而已,而且计算会多一个正余弦计算)。好了,我们再将lβ分解。角度都知道,自然也就得到了lb,lc。这就是克拉克逆变换。

虽然说是逆变换,实际上就是输入输出地位的变换而已。自然的,我们反过来再顺一遍,就知道我们输入uwv,这个力是哪个方向的力了。

二、代码

我的stm32是当时不知道什么时候收藏的一个stm32f407zgt6板子。

主要也是灯哥的代码思路。

首先,我们转动起来,需要去配置一个定时器来输出三路pwm。

void PWM_gpio_init()
{__HAL_RCC_TIM1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();GPIO_InitTypeDef GPIO_InitStruct = {0};GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10; // TIM1_CH1~CH3GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;        // 复用推挽GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;GPIO_InitStruct.Alternate = GPIO_AF1_TIM1;    // TIM1 对应的 AFHAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void PWM_init(uint16_t arr, uint16_t psc)
{PWM_gpio_init();TIM_OC_InitTypeDef sConfigOC = {0};TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};/* 基本定时器配置 */htim1.Instance = TIM1;htim1.Init.Prescaler = 0;                   // 不分频htim1.Init.CounterMode = TIM_COUNTERMODE_CENTERALIGNED1;htim1.Init.Period = MAX_PWM-1;                   // PWM频率 = 168MHz / (8399+1) = 20kHzhtim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;htim1.Init.RepetitionCounter = 0;htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;HAL_TIM_PWM_Init(&htim1);sConfigOC.OCMode = TIM_OCMODE_PWM1;sConfigOC.Pulse = 1400;                        // 初始占空比0sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1);HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2);HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_3);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2);HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_3);
}

这样我们就得到了三个pwm输出。

剩下的foc开环部分用到的代码,讲解一下这个流程。其实就是void velocityOpenloop(float target_velocity)这个函数。核心作用是在开环条件下,根据目标转速更新电机相角并输出对应的 PWM 电压。开环的情况,一般就是我们不算角度,那么角度怎么来呢?

        1.我们可以通过定时器来,比如定时1ms,加上我们需要的速度,那么时间乘以角速度,就是角度了。当然了,这种是不准确的。

        2.我们可以通过读取当前获取的时间,也就是记录上一次进入函数的时间,和本次进入的时间,这两者之差就是运行时间。当然,首先你要有这一个时间获取的方法。我这里是hal库,如果是标准库,或者寄存器,或者其他开发板,就得自己想办法了。

        得到角度之后,我们就知道我们当前的所在的角度。然后输入电压值,电压的大小代表着力矩的大小,同样的,这个电压不能太大。如果太大,可能会烧电机,或者其他问题。根据当前的所在角度,所给力,我们就可以由上边的克拉克,帕克等变换,得到uwv,这时候在给pwm配置,就完成了一次运动。我们将velocityOpenloop放到main函数的while里就可以了。当然,也可以再开一个定时器,把这个放到定时器的回调函数里,这里的时间就是固定的了。可以参考定时器调用开环函数。


float _normalizeAngle(float angle){float a = fmod(angle, 2*PI);   //取余运算可以用于归一化,列出特殊值例子算便知return a >= 0 ? a : (a + 2*PI);  
}void setPhaseVoltage(float Uq,float Ud, float angle_el) {angle_el = _normalizeAngle(angle_el + zero_electric_angle);// 帕克逆变换Ualpha =  -Uq*sin(angle_el); Ubeta =   Uq*cos(angle_el); // 克拉克逆变换Ua = Ualpha + voltage_power_supply/2;Ub = (sqrt(3)*Ubeta-Ualpha)/2 + voltage_power_supply/2;Uc = (-Ualpha-sqrt(3)*Ubeta)/2 + voltage_power_supply/2;setPwm(Ua,Ub,Uc);
}void setPwm(float Ua, float Ub, float Uc) {// 计算占空比// 限制占空比从0到1dc_a = _constrain(Ua / voltage_power_supply, 0.0f , 1.0f );dc_b = _constrain(Ub / voltage_power_supply, 0.0f , 1.0f );dc_c = _constrain(Uc / voltage_power_supply, 0.0f , 1.0f );//写入PWM到PWM 0 1 2 通道__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,dc_a*MAX_PWM);__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_2,dc_b*MAX_PWM);__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_3,dc_c*MAX_PWM);
}
static inline uint32_t micros(void) {return DWT->CYCCNT / (SystemCoreClock / 1000000);
}
void velocityOpenloop(float target_velocity){unsigned long now_us = micros();float Ts = (now_us - open_loop_timestamp) * 1e-6f;if(Ts <= 0 || Ts > 0.5f) Ts = 1e-3f;shaft_angle = _normalizeAngle(shaft_angle + target_velocity*Ts);// 最大只能设置为Uq = voltage_power_supply/2,否则ua,ub,uc会超出供电电压限幅float Uq = voltage_power_supply/8;setPhaseVoltage(Uq,  0, _electricalAngle(shaft_angle, 7));open_loop_timestamp = now_us;  //用于计算下一个时间间隔
}
float _electricalAngle(float shaft_angle, int pole_pairs) {return (shaft_angle * pole_pairs);
}
void DWT_Init(void) {CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; // 使能 DWTDWT->CYCCNT = 0;                                // 清零计数DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;            // 启动
}

讲解的还是过于粗糙了,如果错误,欢迎指正。

智能旋钮(一)---foc开环控制

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

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

相关文章

数据科学与计算:爬虫和数据分析案例笔记

案例 1&#xff1a;中国大学排名爬取与分析 一、任务描述 目标&#xff1a;爬取高三网中国大学排名一览表&#xff0c;提取学校名称、总分、全国排名、星级排名、办学层级等数据&#xff0c;并保存为 CSV 文件。 网址&#xff1a;2021中国的大学排名一览表_高三网 二、任务…

华测科技的3D GPR数据分析

很高兴得到了张总的支持&#xff0c;获得了他们雷达的数据&#xff0c;并写了雷达数据读取和转换文件。1 背景搜索后发现华测实力很强&#xff0c;因为他们可达到100km/h的时速&#xff0c;以前我只知道中电众益可以达到这个速度。2数据格式分析2.1 华测数据因为长时间不编程&a…

最长链(二叉树直径DFS)

题目描述现给出一棵N个结点二叉树&#xff0c;问这棵二叉树中最长链的长度为多少&#xff0c;保证了1号结点为二叉树的根。输入第1行为包含了一个正整数N&#xff0c;为这棵二叉树的结点数&#xff0c;结点标号由1至N。 接下来N行&#xff0c;这N行中的第i行包含两个正整数l[i]…

802.11 Wi-Fi 竞争机制深度分析:CSMA/CA 与 DCF

802.11 Wi-Fi 竞争机制深度分析&#xff1a;CSMA/CA 与 DCF 一、核心机制&#xff1a;CSMA/CA&#xff08;载波侦听多路访问/冲突避免&#xff09; 传统以太网使用 CSMA/CD&#xff08;冲突检测&#xff09;&#xff0c;但无线环境中无法实现冲突检测&#xff0c;因此802.11采用…

【Go语言-Day 36】构建专业命令行工具:`flag` 包入门与实战

Langchain系列文章目录 01-玩转LangChain&#xff1a;从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块&#xff1a;四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain&#xff1a;从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…

C语言——深入理解指针(四)

C语言——深入理解指针&#xff08;四&#xff09; 数组名的意义sizeof&#xff08;数组名&#xff09;&#xff0c;且数组名单独放在sizeof内部&#xff0c;则这里的数组名表示整个数组&#xff0c;计算的是整个数组的大小&数组名&#xff0c;这里的数组名表示的是整个数组…

LeetCode 刷题【42. 接雨水】

42. 接雨水 自己做 解&#xff1a;双指针左右分割容器 class Solution { public:int trap(vector<int>& height) {int res 0;int len height.size();if(len < 2) //构不成一个容器了&#xff0c;直接返回return res;int end len - 1; //右边界int…

网络的基本概念、通信原理以及网络安全问题

目录 1、 什么是网络&#xff1f; &#xff08;1&#xff09;网络的概念与本质 &#xff08;2&#xff09;电压信号的合并与抵消 &#xff08;3&#xff09;电压的本质 2、中转设备 &#xff08;1&#xff09;背景 &#xff08;2&#xff09;中转设备的处理能力与编程能…

Windows下使用WSL2创建Ubuntu子系统(更改安装位置与启动图形桌面)

Windows下使用WSL2创建Ubuntu子系统&#xff08;更改安装位置与启动图形桌面&#xff09; 本文介绍如何使用WSL2创建Ubuntu子系统&#xff0c;并更改安装位置到其他磁盘&#xff0c;并启动图形桌面Xfce4。 WSL 版本: 2.5.7.0 系统版本: Windows11 23H2 相关工具&#xff1a;Mo…

时间泄漏 TemporalLeakage

时间泄漏 TemporalLeakage: 就是后续有事件发生&#xff0c;然后才有了这个结果&#xff0c;但是在该事件发生之前&#xff0c;不应该预测该结果。 Temporal Leakage 问题是往往导致纵向Planning不“果断”。 解决方案&#xff1a;人工标注出时间发生的时刻 真值只监督时间发生…

独立书店数字化转型:绝版书修复档案系统与读者阅读行为分析营销平台

在电商冲击与阅读习惯变迁的双重压力下&#xff0c;独立书店正遭遇 “旧书修复难、新书卖不动” 的生存困境。传统模式中&#xff0c;绝版书修复依赖老师傅经验&#xff0c;单本修复周期长达 2 周&#xff0c;损耗率超 30%&#xff1b;营销缺乏数据支撑&#xff0c;导致客流年均…

const修饰指针用法详解

目录 一、const修饰变量 绕过const限制的问题 二、const修饰指针变量 1、无const修饰的指针 2、const放在*左边 3、const放在*右边 4、*两边都有const 三、使用建议 四、记忆技巧 一、const修饰变量 在C语言中&#xff0c;变量默认是可修改的。如果我们希望某个变量不能…

pcl法线估计的踩坑

1&#xff0c;normalestimation对点云法线的评估&#xff0c;只输出法线向量&#xff0c;并不输出xyz值。如果输出类型是pointnormal&#xff0c;那么这点云的法向量有值&#xff0c;xyz值都是02&#xff0c;添加点云xyz数据。可以使用 pcl::concatenatefields(*a,*b,*c)函数p…

利用Minicsv库解析csv文件的c程序及读入测试

上午的c程序写入xlsx较快但不正确&#xff0c;python程序虽正确但过慢。所以找了一个全部源程序加起来不到4K字节的C语言csv解析库Minicsv&#xff0c;来改写&#xff0c;改写结果如下&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h…

企微用户部门同步HRS系统

企微用户导入HR系统流程说明 概述 本文档详细说明了WechatUserImportServiceImpl.importWechatUsersToHrs()方法的业务流程和实现逻辑。该方法负责将企业微信用户数据同步导入到HR管理系统中&#xff0c;包括员工信息、工作信息和任职记录的创建与更新。 主要功能 数据同步…

告别传统SEO!拥抱下一代流量密码:生成式引擎优化(GEO)实战指南

前言&#xff1a;为什么你的“最佳实践”SEO正在失效&#xff1f;你是否发现&#xff0c;即使严格遵循了谷歌自2019年以来的所有“最佳实践”&#xff0c;你的技术博客或产品文档的流量依旧增长乏力&#xff0c;甚至不升反降&#xff1f;你不是一个人。问题在于&#xff0c;游戏…

week1-[一维数组]传送

week1-[一维数组]传送 题目描述 有 nnn 个传送门&#xff0c;从第 iii 个传送门进去后会被传送到第 aia_iai​ 个传送门&#xff0c;进而被传送到第 aaia_{a_i}aai​​ 个传送门&#xff0c;如此一直下去……小 A 想知道从第 kkk 个传送门进去后&#xff0c;能不能回到第 kkk 个…

【18】目心智能——目心智能 嵌入式一面 ,校招,面试问答记录

目心智能——目心智能 嵌入式一面 &#xff0c;校招&#xff0c;面试问答记录 1 简单自我介绍2 你做了这么多算法&#xff0c;为什么不找算法的&#xff1f;3 我们主要还是软件开发&#xff0c;不做结构设计4 模电知识6 CSDN应该附链接在简历上&#xff0c;稍后发给我&#xff…

C++第二十课:快递运费计算器 / 黑白配+石头剪刀布小游戏

快递运费计算器帮一家快递站点开发一个快递运费计算器&#xff0c;快递站点人员只需要输入包裹重量和地点编号即可计算出对应的运费。假设快递费计算规则如下&#xff1a;首重&#xff1a;3公斤 3公斤以内&#xff1a;1.东三省/宁夏/青海/海南&#xff1a;12元&#xff0c;2.新…

网络安全蓝队常用工具全景与实战指南

摘要 在现代信息系统的安全防护中&#xff0c;蓝队承担着防御、检测、响应和持续改进的核心职责。要实现高效、可持续的防御能力&#xff0c;蓝队需要一整套成熟、可靠的工具集来进行威胁情报收集、日志分析、入侵检测、漏洞评估、端点防护、网络流量监控、事件响应与取证等工作…