直流无刷电机FOC控制算法

直流无刷电机FOC控制算法

文章目录

1、FOC概述

1.1 FOC控制算法介绍

FOC(Field-Oriented Control):直译是磁场定向控制,也被称作矢量控制,是目前无刷直流电机(BLDC)和永磁同步电机(PMSM)高效控制的最优方法之一,FOC算法指的是在通过精确地控制磁场大小与方向,使得电机的运动转矩平稳、噪声小、效率高,并且具有高速的动态响应无刷电机。

2、无刷电机

2.1 无刷电机介绍

无刷电机Brushless Motor)是一种电动机,与传统的有刷电机相比,无刷电机没有刷子和换向器,因此具有更高的效率和可靠性。无刷电机采用电子换向技术,通过电子控制器来实现换向,从而使电机能够自动调整转子磁场与定子磁场之间的相对位置,实现转子的旋转。
无刷电机由定子和转子组成。定子上有若干个线圈,通过电流激励产生磁场。转子上有永磁体或者通过电流激励产生磁场。当电流通过定子线圈时,定子线圈产生的磁场与转子磁场相互作用,使得转子受到力矩作用而旋转。
无刷电机具有以下优点:
1.高效率
:无刷电机没有摩擦损耗和电刷损耗,因此具有更高的效率。
2.高功率密度:无刷电机体积小、重量轻,功率密度高。
3.高速度范围:无刷电机转速范围广,可以实现高速运转。
4.高可靠性:无刷电机没有电刷和换向器,减少了故障点,提高了可靠性。
5.低噪音:无刷电机运行平稳,噪音低。

2.2 无刷电机和永磁同步电机的区别

无刷直流电机 (BLDC)和永磁同步电机 (PMSM)比较相似,两者的主要区别是反电动势的波形.,无刷直流电机 (BLDC)反电动势接近于梯形波, 而 永磁同步电机(PMSM) 反电动势接近于正弦波;
下图是无刷直流电机和永磁同步电机反电动势波形图

在这里插入图片描述

2.3 无刷电机的控制原理

2.3.1 无刷电机工作原理

首先我们回忆下高中知识——安培定则,也叫右手螺旋定则,是表示电流和电流激发磁场的磁感线方向间关系的定则。我们这里利用定则之一:当用右手握住通电螺线管,让四指指向电流的方向,那么大拇指所指的那一端是通电螺线管的 N 极。如下图所示:

在这里插入图片描述


根据通电线圈会产生磁场,我们可以把通电线圈的磁场看成一个磁体,如下图:

在这里插入图片描述


磁体之间,存在异性相吸,同性相斥的原理,通电线圈和永磁体之间同样存在,而无刷电机就是利用了通电线圈和永磁体的相互作用原理,下面看下 BLDC(内置转子式无刷电机) 的内部结构图:

在这里插入图片描述


无刷电机有 3 根电机线按顺序依次叫 U 相线(一般为黄色),V 相线(一般为绿色)和 W 相线(一般为蓝色),3 组漆包线绕组的一端连接在一起,另外一端引出即为 UVW 相线,所以任意两根相线通电都可以导通这两个线圈;

2.3.2 直流无刷电机驱动原理

2.3.2.1 有感直流无刷电机六步换相驱动原理

直流无刷电机驱动电路由三个半桥控制电路组成,通过控制三个半桥的上下桥导通和关断,实现逆变控制,将直流电变成交流电,简单点理解就是可以实现流过电机三相线圈的电流的流向控制,是通过使用三相你变电路来实现驱动电机,如下图所示;
所谓的三相逆变电路就是由三个半桥构成的电路,如上图中的 A+与 A-为一个半桥,B+与 B-以及 C+与 C-各自又为一个半桥,共三个半桥;这三个半桥各自控制对应的 A、B、C 三相绕组;当控制 A 的上桥臂 A+导通时,此时 A 相绕组接到电源正,当控制 B 的下桥臂B-导通时,此时 B 相绕组接到电源负,所以此时电流由 A 流向 B。

在这里插入图片描述


由于有感直流无刷电机的运行方式为绕组两两导通,所以三相线圈的导通组合只有 6 种通电情况,根据合理的顺序依次切换通电顺序即可让转子跟着磁场转起来。如下图是六步换相导通的情况:

在这里插入图片描述


想要控制无刷电机绕组的极性,只需要控制绕组对应半桥的“上桥臂导通”或者“下桥臂导通”就可以实现控制该相连接至“正极”或者“负极”了,但是要注意不可以同侧半桥上下桥臂同时导通,负责会短路,烧毁电机!要实现6 步换相控制无刷电机转起来,就可以通过三相逆变电路来实现,如下图 ;

在这里插入图片描述


无刷电机依靠传感器提供转子位置信息进行驱动的方式我们称之为有感驱动方式,直流无刷电机六步换相控制需要通过霍尔传感器判断电机转子的位置,无刷电机的传感器一般为霍尔传感器,根据霍尔器件可检测磁场的变化的特性再搭配一定的电路将磁场方向变化信号转化成不同的高低电平信号输出;
霍尔传感器安装的以 120°电角度所安装,如下图所示;

在这里插入图片描述

下图为电机旋转时三个霍尔传感器输出的波形,所对应的扇区组合。通过三个霍尔传感器输出的波形就可以判断当前转子的具体位置,同样满足 6 步一周期。

在这里插入图片描述


六步换向需要依赖霍尔传感器反馈的转子位置,其相对应的就是三相逆变电路的上下桥臂导通情况,如下表所示。

在这里插入图片描述


下图为直流无刷电机六步换相控制动态图;

在这里插入图片描述

下图为有感驱动无刷电机整体框图;

在这里插入图片描述
2.3.2.2 直流无刷电机FOC控制原理

我们从原理上简单的讲解了下FOC和六步换向的区别,而在实际控制中,FOC与六步换相还存在以下差别:
(1)控制信号区别:FOC采用正弦波驱动,六步换相采用方波驱动;
(2)控制方式区别:FOC控制中三个半桥的MOS采用三三导通,而六步换相采用两两导通

3、无刷电机FOC控制算法

3.1 FOC控制算法整体流程

下面是FOC控制算法的流程图:

在这里插入图片描述


FOC控制算法的实现流程,主要氛围以下几大步:
(1)采集电机三相相电流 Ia Ib Ic
(2)将三相相电流通过 Clark 变化得到 Iα Iβ
(3)将 Iα Iβ 通过 Park 变化得到 Id Iq
(4)根据 Id Iq 和目标 Id_target Iq_target 进行 PID 计算得到 Uq Ud (电流环)
(5)将 Uq Ud 通过反 Park 变换得到 Uα Uβ
(6)将 Uα Uβ 作为SVPWM的输入,得到三路半桥的PWM输出定时器的比较寄存器值CCR

3.2 FOC算法Clarke变换

clark变化也就是将无刷电机静止的三相相电流 Ia Ib Ic三相坐标系转化为静止的 α-β 两相直角坐标系。
下图为三相相电流 Ia Ib Ic三相坐标系的动态图

在这里插入图片描述


下图为转换成α-β 两相直角坐标系的动态图

在这里插入图片描述

3.2.1 Clarke变换公式推导

通过ADC采样得到电机的Ia和Ib两项电流信息,由于基尔霍夫电流定律(公式:Ia + Ib + Ic = 0),同一个节点流入电流值与流出电流相等,我们可以计算出Ic,三个电流的相位差为120°,如下图所示;

在这里插入图片描述


通过Clark变换,将三相定子坐标系(三个轴互为120°,Ia , Ib , Ic)转化为两相的定子直角坐标系(i α , i β)这个过程有点类似于力的矢量分解,把三相映射到两相的坐标轴之上,如下图所示。

在这里插入图片描述


根据上图把三相映射到两相的坐标轴之上,可以得出Clarke变换的推导公式为:

在这里插入图片描述


将上式写成矩阵形式:

在这里插入图片描述


上式中,系数K = 2/3,变换前后,幅值不变,(既合成矢量的大小和方向相等),等幅值变换其实就是将Iα =Ia,将系数K = 2/3代入上式得

在这里插入图片描述

再根据基尔霍夫电流定律Ia + Ib + Ic = 0得出等幅值Clarke变换的最终结果为:

在这里插入图片描述


在这里插入图片描述

3.2.2 Clarke逆变换公式推导

我们学习了怎么把一个三相时域上的复杂问题用矢量表示,并且用克拉克变换对它进行了降维,得到了降维后的简化表达形式。那么,有没有什么办法能够反过来把降维后的形式重新升维变回原来的Ia,Ib,Ic三相电流波形呢?有,这就被称为克拉克逆变换。这个在后续的FOC算法中也会很常用到。趁热打铁,我们来看一看怎么进行克拉克逆变换。
我们已经知道了克拉克变换后的Iα 、Iβ,我们在此基础上研究Clarke逆变换,首先,Ia的逆变换我们是不需要研究的,因为我们已经知道了Iα =Ia。

在这里插入图片描述


进一步的,我们研究逆变换Ib:

在这里插入图片描述


最后,还是根据基尔霍夫电流定律:Ia + Ib + Ic = 0,我们得到逆变换Ic:

在这里插入图片描述


则克拉克逆变换三式皆得,总结如下:

在这里插入图片描述

3.3 FOC算法Park变换

将电机三相相电流通过 Clark 变化得到 Iα Iβ,然后再将Iα Iβ通过变换得到随电机转子转动的Iq Id坐标系称为Park变换。

3.3.1 Park变换公式推导

在这里插入图片描述

根据上图,角度θ是d轴与两相静止坐标系α轴的夹角。根据三角关系推出,Iα在d轴上的投影分量为Iαcosθ,q轴与β轴的夹角为θ2,可以得出θ2 = θ,因此iβ在d轴上的投影分量为iβsinθ; iα在q轴上的投影分量为-iαsinθ,因为它的投影分量在q轴的负方向上; iβ在q轴上的投影分量为iβscosθ。综合以上,可以得出公式:

在这里插入图片描述


这个id,iq坐标系是始终跟着转子旋转的;
(1)d 轴方向与转子磁链方向重合,又叫直轴;
(2)q 轴方向与转子磁链方向垂直,又叫交轴;

在这里插入图片描述


经过这一步的变换,我们会发现,一个匀速旋转向量在这个坐标系下变成了一个定值,这个坐标系下两个控制变量都被线性化了,如下图所示;

在这里插入图片描述

3.3.2 Park逆变换公式推导

在这里插入图片描述


Vd在β轴上的投影分量为Vdsinθ,Vq在β轴上的投影分量为Vqcosθ,由此可得出下式:

在这里插入图片描述

3.4 FOC算法SVPWM(空间矢量脉冲调制)原理及实现

3.4.1 SVPWM原理及实现

SVPWMSpace Vector Pulse Width Modulation)即空间矢量脉宽调制。它通过三项你变器的6个功率管输出随时间变化的PWM波,模拟三项对称正弦波电流形成的电压矢量园,产生接近圆形的磁链轨迹。SVPWM的原理如下:
(1)基本矢量电压:SVPWM将三相电压分解为两个正弦波和一个直流分量,这三个分量构成了基本矢量电压。
(2)扇区判断:根据电机的电角度,判断当前所处的扇区。扇区是将电机的360度分为六个等分,每个扇区对应一个基本矢量电压。
(3)计算相邻两个基本矢量电压的作用时间:根据当前所处的扇区,计算相邻两个基本矢量电压的作用时间。作用时间是指每个基本矢量电压在一个电周期内的持续时间。
(4)三路PWM占空比计算:根据相邻两个基本矢量电压的作用时间,计算三相PWM的占空比。占空比是指PWM信号高电平的持续时间与一个电周期的比值。
算法流程如下:
step1
:根据电机的电角度,判断当前所处的扇区。
step2:根据当前所处的扇区,计算相邻两个基本矢量电压的作用时间。
step3:根据相邻两个基本矢量电压的作用时间,计算三相PWM的占空比。

3.4.2 七段式SVPWM和五段式SVPWM的区别

七段式SVPWM(Space Vector Pulse Width Modulation)和五段式SVPWM都是一种常用的交流电机控制方法,它们的主要区别在于矢量分解时所使用的向量数不同。
(1)七段式:七段式SVPWM使用七个不同的向量进行矢量分解,可以得到更高的电机效率和更低的谐波失真率。但是,七段式SVPWM需要更复杂的计算,因此需要更高的控制精度和计算能力。
(2)五段式:五段式SVPWM只使用五个向量进行矢量分解,计算较为简单,适用于控制较为简单的电机系统。但是,五段式SVPWM相对于七段式SVPWM的效率和失真率会略差一些。
本设计采用七段式SVPWM设计;

七段式SVPWM波形图


七段式SVPWM波形图

3.4.3 基本矢量电压

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

3.4.4 扇区判断

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

3.4.5 相邻两个基本矢量电压的作用时间

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述


在这里插入图片描述

3.4.6 根据时间计算三路PWM占空比

在这里插入图片描述


根据上图(以扇区一为例)可以得出三路PWM占空比值的公式:
value_a = (tpwm - Ta - Tb)/4;
value_b = value_a + Ta/2;
value_c = value_b + Tb/2;

value_a:占空比占比最多;
value_b:占空比占比中等;
value_c:占空比占比最少;

每个扇区A、B、C占空比占比都不一样,根据3.4.2六个扇区的七段式波形图,得出的value_a、value_b、value_c代入相对应的扇区;

3.5 FOC矢量控制C语言代码

3.5.1 FOC矢量控制foc.c文件代码

#include"foc.h"//反Park变换,将静止两相坐标系D/Q转换为旋转两相坐标系Valpha/VbetavoidRevParkOperate(float vd,float vq,float theta,float*valpha,float*vbeta){*valpha = vd *cos(theta)- vq *sin(theta);*vbeta = vd *sin(theta)+ vq *cos(theta);}//扇区判断函数,通过valpha和vbeta判断扇区//返回值:315462对应扇区123456unsignedcharSectorJude(float valpha,float vbeta){float A = vbeta;float B = valpha * sqrt3/2.0f- vbeta/2.0f;float C =-valpha * sqrt3/2.0f- vbeta/2.0f;unsignedchar N =0;if(A >0){ N = N+1;}if(B >0){ N = N+2;}if(C >0){ N = N+4;}return N;// float U1 = vbeta;// float U2 = valpha * sqrt3/2.0f - vbeta/2.0f;// float U3 = -valpha * sqrt3/2.0f - vbeta/2.0f;// unsigned char A = 0,B = 0,C = 0,N = 0;// // A= (U1>0)? 1:0;// B= (U2>0)? 1:0;// C= (U3>0)? 1:0;// // N = A + 2*B + 4*C;// // return N;}//矢量作用时间计算voidVectorActionTime(uint8_t n,float valpha,float vbeta,uint32_t udc,uint32_t tpwm,float*ta,float*tb){float X =(sqrt3 * tpwm)/ udc * vbeta;float Y =(sqrt3 * tpwm)/ udc *((sqrt3/2.0f)*valpha - vbeta/2.0f);float Z =(sqrt3 * tpwm)/ udc *(-(sqrt3/2.0f)*valpha - vbeta/2.0f);if(n ==3)//第一扇区{*ta = Y;*tb = X;}if(n ==1)//第二扇区{*ta =-Y;*tb =-Z;}if(n ==5)//第三扇区{*ta = X;*tb = Z;}if(n ==4)//第四扇区{*ta =-X;*tb =-Y;}if(n ==6)//第五扇区{*ta = Z;*tb = Y;}if(n ==2)//第六扇区{*ta =-Z;*tb =-X;}}//CCR时间计算voidCCRCalculate(uint8_t n,float ta,float tb,uint32_t tpwm,uint32_t*ccr1,uint32_t*ccr2,uint32_t*ccr3){/*限制ta和tb,ta+tb不能超过tpwm*/float temp = ta + tb;if(temp > tpwm){ ta = ta / temp*tpwm; tb = tb / temp*tpwm;}float value1 =(tpwm - ta - tb)/4.0f;float value2 = value1 + ta/2.0f;float value3 = value2 + tb/2.0f;switch(n){case3:*ccr1 = value1;*ccr2 = value2;*ccr3 = value3;break;case1:*ccr1 = value2;*ccr2 = value1;*ccr3 = value3;break;case5:*ccr1 = value3;*ccr2 = value1;*ccr3 = value2;break;case4:*ccr1 = value3;*ccr2 = value2;*ccr3 = value1;break;case6:*ccr1 = value2;*ccr2 = value3;*ccr3 = value1;break;case2:*ccr1 = value1;*ccr2 = value3;*ccr3 = value2;break;}}//通过Vd,Vq,THETA,Udc,Tpwm计算每一步的CCR值并写入定时器/* Vd:给电机Vd的电压 Vq:给电机Vq的电压 theta:电角度 theta:母线电压 tpwm:PWM周期 */voidSvpwmAlgorithm(float vd,float vq,float theta,uint32_t udc,uint32_t tpwm){float valpha =0;float vbeta =0;RevParkOperate(vd,vq,theta,&valpha,&vbeta);//计算当前valpha和vbetaunsignedchar n =SectorJude(valpha,vbeta);//计算当前扇区float ta =0;float tb =0;VectorActionTime(n,valpha,vbeta,udc,tpwm,&ta,&tb);//计算两个矢量的作用时间uint32_t ccr1 =0;uint32_t ccr2 =0;uint32_t ccr3 =0;CCRCalculate(n,ta,tb,tpwm,&ccr1,&ccr2,&ccr3);//CCR时间计算(计算占空比值)__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_1,ccr1);//输出三路占空比__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_2,ccr2);__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_3,ccr3);}

3.5.1 FOC矢量控制foc.h文件代码

#ifndef__FOC_H__#define__FOC_H__#include"tim.h"#include<math.h>#include<stdio.h>#definesqrt31.7320508fvoidSvpwmAlgorithm(float vd,float vq,float theta,uint32_t udc,uint32_t tpwm);voidClark_Park(float Electronic_Angle);floatmotor_ramp(float t_value,float acc_time);#endif

4、STM32CUBEMX配置

4.1、时钟原配置

在这里插入图片描述

4.2、调试接口配置

在这里插入图片描述

4.3、时钟配置

在这里插入图片描述

4.4、高级定时器配置(用于FOC算法,产生PWM)

在这里插入图片描述


在这里插入图片描述

4.5、ADC配置(用于电机三相电流采样)

在这里插入图片描述


在这里插入图片描述

5、代码讲解

5.1、foc算法控制算法代码.c文件

#include"foc.h"#include"spi.h"#include"adc.h" FOC_CURRENT foc_current;//反Park变换,将静止两相坐标系D/Q转换为旋转两相坐标系Valpha/VbetavoidRevParkOperate(float vd,float vq,float theta,float*valpha,float*vbeta){*valpha = vd *cos(theta)- vq *sin(theta);*vbeta = vd *sin(theta)+ vq *cos(theta);}//扇区判断函数,通过valpha和vbeta判断扇区//返回值:315462对应扇区123456unsignedcharSectorJude(float valpha,float vbeta){float A = vbeta;float B = valpha * sqrt3/2.0f- vbeta/2.0f;float C =-valpha * sqrt3/2.0f- vbeta/2.0f;unsignedchar N =0;if(A >0){ N = N+1;}if(B >0){ N = N+2;}if(C >0){ N = N+4;}return N;// float U1 = vbeta;// float U2 = valpha * sqrt3/2.0f - vbeta/2.0f;// float U3 = -valpha * sqrt3/2.0f - vbeta/2.0f;// unsigned char A = 0,B = 0,C = 0,N = 0;// // A= (U1>0)? 1:0;// B= (U2>0)? 1:0;// C= (U3>0)? 1:0;// // N = A + 2*B + 4*C;// // return N;}//矢量作用时间计算voidVectorActionTime(uint8_t n,float valpha,float vbeta,uint32_t udc,uint32_t tpwm,float*ta,float*tb){float X =(sqrt3 * tpwm)/ udc * vbeta;float Y =(sqrt3 * tpwm)/ udc *((sqrt3/2.0f)*valpha - vbeta/2.0f);float Z =(sqrt3 * tpwm)/ udc *(-(sqrt3/2.0f)*valpha - vbeta/2.0f);if(n ==3)//第一扇区{*ta = Y;*tb = X;}if(n ==1)//第二扇区{*ta =-Y;*tb =-Z;}if(n ==5)//第三扇区{*ta = X;*tb = Z;}if(n ==4)//第四扇区{*ta =-X;*tb =-Y;}if(n ==6)//第五扇区{*ta = Z;*tb = Y;}if(n ==2)//第六扇区{*ta =-Z;*tb =-X;}}//CCR时间计算voidCCRCalculate(uint8_t n,float ta,float tb,uint32_t tpwm,uint32_t*ccr1,uint32_t*ccr2,uint32_t*ccr3){/*限制ta和tb,ta+tb不能超过tpwm*/float temp = ta + tb;if(temp > tpwm){ ta = ta / temp*tpwm; tb = tb / temp*tpwm;}float value1 =(tpwm - ta - tb)/4.0f;float value2 = value1 + ta/2.0f;float value3 = value2 + tb/2.0f;switch(n){case3:*ccr1 = value1;*ccr2 = value2;*ccr3 = value3;break;case1:*ccr1 = value2;*ccr2 = value1;*ccr3 = value3;break;case5:*ccr1 = value3;*ccr2 = value1;*ccr3 = value2;break;case4:*ccr1 = value3;*ccr2 = value2;*ccr3 = value1;break;case6:*ccr1 = value2;*ccr2 = value3;*ccr3 = value1;break;case2:*ccr1 = value1;*ccr2 = value3;*ccr3 = value2;break;}}//通过Vd,Vq,THETA,Udc,Tpwm计算每一步的CCR值并写入定时器voidSvpwmAlgorithm(float vd,float vq,float theta,uint32_t udc,uint32_t tpwm){float valpha =0;float vbeta =0;RevParkOperate(vd,vq,theta,&valpha,&vbeta);//计算当前valpha和vbetaunsignedchar n =SectorJude(valpha,vbeta);//计算当前扇区float ta =0;float tb =0;VectorActionTime(n,valpha,vbeta,udc,tpwm,&ta,&tb);//计算两个矢量的作用时间uint32_t ccr1 =0;uint32_t ccr2 =0;uint32_t ccr3 =0;CCRCalculate(n,ta,tb,tpwm,&ccr1,&ccr2,&ccr3);//CCR时间计算(计算占空比值)__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_1,ccr1);//输出三路占空比__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_2,ccr2);__HAL_TIM_SET_COMPARE(&htim8,TIM_CHANNEL_3,ccr3);}/*FOC-Park和Clark变换*//* APhaseCurrent:电机A相电流 BPhaseCurrent:电机B相电流 Electronic_Angle:电角度 *Current:Park、Clark变换之后的电流值 */voidClark_Park(int APhaseCurrent,int BPhaseCurrent,float Electronic_Angle,FOC_CURRENT *Current){//Clark变换 I_alfa = APhaseCurrent; I_beta =1/sqrt3 *(2*BPhaseCurrent + APhaseCurrent);//Park变换 foc_current.Id = I_alfa*cos(Electronic_Angle)+ I_beta*sin(Electronic_Angle); foc_current.Iq =-(I_alfa *sin(Electronic_Angle))+ I_beta*cos(Electronic_Angle); foc_current.Id = foc_current.Id/1600.0; foc_current.Iq = foc_current.Iq/1600.0;}

5.2、foc算法控制算法代码.h文件

#ifndef__FOC_H__#define__FOC_H__#include"tim.h"#include<math.h>#include<stdio.h>#definesqrt31.7320508f/*FOC变换之后的电流值*/typedefstruct{float Id;float Iq;}FOC_CURRENT;extern FOC_CURRENT foc_current;voidSvpwmAlgorithm(float vd,float vq,float theta,uint32_t udc,uint32_t tpwm);voidClark_Park(int APhaseCurrent,int BPhaseCurrent,float Electronic_Angle,FOC_CURRENT *Current);#endif

5.3、主要运行代码

/*TIM3回调函数*/voidHAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)/*进入中断时间为1ms秒*/{if(htim->Instance==TIM3){if(motor_state ==1){Get_Pos();//编码器多圈数据累加 Encoder_TypeDef.angle =Get_Elec_Angle();//获取机械角度/*角度补偿 Encoder_TypeDef.angle:电机的机械角度 Encoder_TypeDef.angle_rad_offset:电机零位的编码器的值 */if(Encoder_TypeDef.angle>=Encoder_TypeDef.angle_rad_offset){ Encoder_TypeDef.angle = Encoder_TypeDef.angle - Encoder_TypeDef.angle_rad_offset;}else{ Encoder_TypeDef.angle =6.2831852f- Encoder_TypeDef.angle_rad_offset + Encoder_TypeDef.angle;} Encoder_TypeDef.electronic_angle = Encoder_TypeDef.angle*7;//将机械角度转换成电角度 Encoder_TypeDef.electronic_angle =fmod(Encoder_TypeDef.electronic_angle,6.2831852f);//将电角度限制在0-6.2831852f之间/*位置环*/ PID_Position_Out =PID_Function(&pid_position_TypeDef,target_location,encoder.rad_comulative);//PID输出/*速度计算*/ vel_LPF =LPF_velocity(MT6701_GetVelocity());//速度计算以及低通滤波处理/*速度环*/ PID_Speed_Out =PID_Function(&pid_speed_TypeDef,PID_Position_Out,vel_LPF);//PID输出/*Clark_Park变换*/Clark_Park(PhaseACurrent,PhaseBCurrent,Encoder_TypeDef.electronic_angle,&foc_current);/*电流环*/ PID_Out_Value =PID_Function(&pid_current_Typedef,PID_Speed_Out,foc_current.Iq);//PID输出SvpwmAlgorithm(0,PID_Out_Value,Encoder_TypeDef.electronic_angle,12,3600);//SVPWM算法 }}}

Read more

【算法通关指南:算法基础篇 】模拟算法专题:1. 铺地毯 2. 回文日期 3. 扫雷

【算法通关指南:算法基础篇 】模拟算法专题:1. 铺地毯 2. 回文日期 3. 扫雷

🔥小龙报:个人主页 🎬作者简介:C++研发,嵌入式,机器人方向学习者 ❄️个人专栏:《算法通关指南》 ✨ 永远相信美好的事情即将发生 文章目录 * 前言 * 一、模拟算法 * 二、模拟的经典算法题 * 2.1 铺地毯 * 2.1.1题目 * 2.1.2 算法原理 * 2.1.3代码 * 2.2 回文日期 * 2.2.1题目 * 2.2.2 算法原理 * 2.2.3代码 * 2.2.3.1 枚举月 + 日 * 2.2.

By Ne0inhk
算法王冠上的明珠——动态规划之路径问题(第一篇)

算法王冠上的明珠——动态规划之路径问题(第一篇)

目录 1. 什么叫路径类动态规划 一、核心定义(通俗理解) 二、核心特征(识别这类问题的关键) 2. 动态规划步骤 状态表示 状态转移方程 初始化 填表顺序 返回值 3. 例题讲解 3.1 LeetCode62. 不同路径 3.2 LeetCode63. 不同路径 II 3.3 LeetCodeLCR 166. 珠宝的最高价值 今天我们来聊一聊动态规划的路径类问题。 1. 什么叫路径类动态规划 路径类动态规划是 动态规划的一个重要分支,核心解决 “从起点到终点的路径相关问题”—— 比如 “路径总数”“最短路径长度”“路径上的最大 / 最小和” 等,其本质是通过 “状态递推” 避免重复计算,高效求解多阶段决策的路径问题。 一、

By Ne0inhk
马年“码”上发力:用Manacher“马拉车”算法,拉平最长回文难题

马年“码”上发力:用Manacher“马拉车”算法,拉平最长回文难题

💗博主介绍:计算机专业的一枚大学生 来自重庆 @燃于AC之乐✌专注于C++技术栈,算法,竞赛领域,技术学习和项目实战✌ 💗根据博主的学习进度更新(可能不及时) 💗后续更新主要内容:C语言,数据结构,C++、linux(系统编程和网络编程)、MySQL、Redis、QT、Python、Git、爬虫、数据可视化、小程序、AI大模型接入,C++实战项目与学习分享。 👇🏻 精彩专栏 推荐订阅👇🏻 点击进入🌌作者专栏🌌: 算法画解 ✅ C++ ✅ 🌟算法相关题目点击即可进入实操🌟 感兴趣的可以先收藏起来,请多多支持,还有大家有相关问题都可以给我留言咨询,希望希望共同交流心得,一起进步,你我陪伴,学习路上不孤单! 文章目录 * 前言 * Manacher(马拉车)算法 * 问题: * 1.相关概念引入

By Ne0inhk
【强化学习】近端策略优化算法(PPO)万字详解(附代码)

【强化学习】近端策略优化算法(PPO)万字详解(附代码)

📢本篇文章是博主强化学习(RL)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅解。文章分类在👉强化学习专栏:        【强化学习】- 【单智能体强化学习】(9)---《近端策略优化算法(PPO)详解》 近端策略优化算法(PPO)详解 目录 PPO算法介绍 1. 背景 2. PPO 的核心思想 3. PPO 流程 4. 为什么 PPO 很强? 5. PPO 的直观类比 PPO算法的流程推导及数学公式 1. 背景与目标 2. PPO的概率比率 3. 优化目标 4. 值函数优化 5. 策略熵正则化

By Ne0inhk