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

小知识点二:无刷电机开环控制

0 前言

该部分只用于自学使用,作为笔记方便后续自查。
资料参考:http://dengfoc.com

1 开环速度控制理论

根据上一节的知识,首先如果我们知道一个矢量( I q I_q Iq​和 I d I_d Id​可以合成一个矢量)和一个 θ \theta θ就能反向求出 α \alpha α β \beta β上的电流,从而再通过克拉克逆变换求出 I A 、 I B 、 I C I_{A} 、I_{B} 、I_{C} IAIBIC,再通过PWM控制控制板的引脚输出指定大小的电流就可以控制电机转子按照我们想要的方式转动。

暂时先只考虑电压控制,所有的理论与之前一致。

那开环速度控制会是怎样的呢?

目的:理论上这件事情应该是我输入速度,那电机转子就会根据我输入的命令进行转动。

step1:上一节中的知识告诉我们需要一个矢量和一个电角度,我才能控制转子运动,那么问题就转变为如何根据现在的速度获得一个矢量和一个电角度。

首先,我们先给出一个公式:电角度=机械角度*极对数,极对数是电机故有的值,机械角度就是我们能看到的电机的旋转。

若我们指定电机速度为 v c o n t r o l l r a d / s v_{controll}rad/s vcontrollrad/s,那么在指定的时间 T s T_s Ts下可以转 v c o n t r o l l ∗ T s r a d v_{controll}*T_srad vcontrollTsrad,如果默认初始机械角度为0,那么 T s T_s Ts时刻机械角度应该为 0 + v c o n t r o l l ∗ T s 0+v_{controll}*T_s 0+vcontrollTs 2 ∗ T s 2*T_s 2Ts时刻机械角度应该为 0 + v c o n t r o l l ∗ T s + v c o n t r o l l ∗ T s 0+v_{controll}*T_s+v_{controll}*T_s 0+vcontrollTs+vcontrollTs

theta=0
while Ture:#假设每次循环时间为T_s
theta=theta+v_{controll}*T_s

但是这个角度会一直增加所以要根据周期性把弧度范围限制在 [ 0 , 2 π ] [0,2\pi] [0,2π]之间,并通过 电角度=机械角度*极对数 将机械角度转化为电角度。

step2:已知这个矢量 U q U_q Uq,及step1计算出的电角度 θ \theta θ,我们就可以通过帕克变换将其转换到 α − β \alpha-\beta αβ上。
在这里插入图片描述
U α = − s i n ( θ ) ∗ U q U_{\alpha}=-sin(\theta)*U_q Uα=sin(θ)Uq
U β = c o s ( θ ) ∗ U q U_{\beta}=cos(\theta)*U_q Uβ=cos(θ)Uq

step3:已知 U α 、 U β U_{\alpha}、 U_{\beta} UαUβ可以通过克拉克逆变换转换到 A − B − C A-B-C ABC
U A = U α U_{A}=U_{\alpha} UA=Uα
U B = 3 U β − U α 2 U_{B}=\frac{\sqrt{3}U_{\beta}-U_{\alpha}}{2} UB=23 UβUα
U C = − U α − 3 U β 2 U_{C}=\frac{-U_{\alpha}-\sqrt{3}U_{\beta}}{2} UC=2Uα3 Uβ

1 开环速度控制代码

// #include<arduino.h>
#include <Arduino.h>  // 正确写法
/*** 这部分根据开环速度控制课程部分整理(以及注意实际上这个控制器完全可以由单片机代替)* 主要看实现方式以及异同* 需要注意哪里的修改*///PWM输出引脚定义
int pwmA = 4;
int pwmB = 2;
int pwmC = 13;//初始变量及函数定义
#define _constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
//宏定义实现的一个约束函数,用于限制一个值的范围。
//具体来说,该宏定义的名称为 _constrain,接受三个参数 amt、low 和 high,分别表示要限制的值、最小值和最大值。该宏定义的实现使用了三元运算符,根据 amt 是否小于 low 或大于 high,返回其中的最大或最小值,或者返回原值。
//换句话说,如果 amt 小于 low,则返回 low;如果 amt 大于 high,则返回 high;否则返回 amt。这样,_constrain(amt, low, high) 就会将 amt 约束在 [low, high] 的范围内。float voltage_power_supply=12.6; //设定板子供电电压
float shaft_angle=0,open_loop_timestamp=0;
float zero_electric_angle=0,Ualpha,Ubeta=0,Ua=0,Ub=0,Uc=0,dc_a=0,dc_b=0,dc_c=0;// 初始化代码放在这里
void setup() {// put your setup code here, to run once:// 加载一个串口,方便测试// 串口初始化定义Serial.begin(115200);//PWM设置,设置输出的引脚口:即4,2,13是输出的引脚pinMode(pwmA, OUTPUT);pinMode(pwmB, OUTPUT);pinMode(pwmC, OUTPUT);//配置引脚PWM的输出模式//ledcAttachPin(pwmA, 0);ledcAttachPin(pwmB, 1);ledcAttachPin(pwmC, 2);// 频率30000,是只PWM周期1/30000秒(周期非常快),输出精度是8位(根据每个周期的占空比进行计算)ledcSetup(0, 30000, 8);  //pwm频道, 频率, 精度ledcSetup(1, 30000, 8);  //pwm频道, 频率, 精度ledcSetup(2, 30000, 8);  //pwm频道, 频率, 精度Serial.println("完成PWM初始化设置");delay(3000);//等待3秒pinMode(25, OUTPUT);     //使能引脚设置高电平
}// 电角度求解 电角度=机械角度*极对数=shaft_angle * pole_pairs
float _electricalAngle(float shaft_angle, int pole_pairs) {return (shaft_angle * pole_pairs);
}// 归一化角度到 [0,2PI] 其实是将角度限制在[0,2PI]
float _normalizeAngle(float angle){float a = fmod(angle, 2*PI);   //取余运算可以用于归一化,列出特殊值例子算便知return a >= 0 ? a : (a + 2*PI);  //三目运算符。格式:condition ? expr1 : expr2 //其中,condition 是要求值的条件表达式,如果条件成立,则返回 expr1 的值,否则返回 expr2 的值。可以将三目运算符视为 if-else 语句的简化形式。//fmod 函数的余数的符号与除数相同。因此,当 angle 的值为负数时,余数的符号将与 _2PI 的符号相反。也就是说,如果 angle 的值小于 0 且 _2PI 的值为正数,则 fmod(angle, _2PI) 的余数将为负数。//例如,当 angle 的值为 -PI/2,_2PI 的值为 2PI 时,fmod(angle, _2PI) 将返回一个负数。在这种情况下,可以通过将负数的余数加上 _2PI 来将角度归一化到 [0, 2PI] 的范围内,以确保角度的值始终为正数。
}// 设置PWM到控制器输出
//Ua Ub Uc是已经算出来的结果
void setPwm(float Ua, float Ub, float Uc) {// 本来的函数中还有一个Ua Ub Uc的上限设置,这里没有// 计算占空比// 限制占空比从0到1// 实际上相当于想用PWM来表示连续电压,以整个周期看作1的话,那么占空比实际上就是实际电压/最大能达到的电压dc_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 通道// Arduino 的 ledcWrite() 函数使用 8 位分辨率(默认)// 8 位 = 2⁸ = 256 个可能值(0 到 255)// 0 表示 0% 占空比(始终低电平)// 255 表示 100% 占空比(始终高电平)ledcWrite(0, dc_a*255);ledcWrite(1, dc_b*255);ledcWrite(2, dc_c*255);
}// 这个函数就是进行克拉克变换和帕克变换(Uq实际上就是力矩的大小)
void setPhaseVoltage(float Uq,float Ud, float angle_el) {angle_el = _normalizeAngle(angle_el + zero_electric_angle);// 帕克逆变换// 这里注意实际上只用的Uq,没有用UdUalpha =  -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);
}//开环速度函数    Uq和电角度生成器
float velocityOpenloop(float target_velocity){//输入:目标速度,大概是弧度每秒这么一个单位unsigned long now_us = micros();  //获取从开启芯片以来的微秒数,它的精度是 4 微秒。 micros() 返回的是一个无符号长整型(unsigned long)的值//计算当前每个Loop的运行时间间隔float Ts = (now_us - open_loop_timestamp) * 1e-6f;//由于 micros() 函数返回的时间戳会在大约 70 分钟之后重新开始计数,在由70分钟跳变到0时,TS会出现异常,因此需要进行修正。如果时间间隔小于等于零或大于 0.5 秒,则将其设置为一个较小的默认值,即 1e-3fif(Ts <= 0 || Ts > 0.5f) Ts = 1e-3f;// 通过乘以时间间隔和目标速度来计算需要转动的机械角度,存储在 shaft_angle 变量中。在此之前,还需要对轴角度进行归一化,以确保其值在 0 到 2π 之间。shaft_angle = _normalizeAngle(shaft_angle + target_velocity*Ts);//以目标速度为 10 rad/s 为例,如果时间间隔是 1 秒,则在每个循环中需要增加 10 * 1 = 10 弧度的角度变化量,才能使电机转动到目标速度。//如果时间间隔是 0.1 秒,那么在每个循环中需要增加的角度变化量就是 10 * 0.1 = 1 弧度,才能实现相同的目标速度。因此,电机轴的转动角度取决于目标速度和时间间隔的乘积。// 使用早前设置的voltage_power_supply的1/3作为Uq值,这个值会直接影响输出力矩// 最大只能设置为Uq = voltage_power_supply/2,否则ua,ub,uc会超出供电电压限幅float Uq = voltage_power_supply/3;setPhaseVoltage(Uq,  0, _electricalAngle(shaft_angle, 7));open_loop_timestamp = now_us;  //用于计算下一个时间间隔return Uq;
}void loop() {digitalWrite(25, HIGH);// put your main code here, to run repeatedly:velocityOpenloop(10);
}
http://www.xdnf.cn/news/13616.html

相关文章:

  • 创建型设计模式
  • linux系统实时监控top命令
  • Spring Boot 完整教程 - 从入门到精通(全面版)
  • 鹰盾视频加密器播放器倍速播放中变速不变声的技术原理解析
  • 开源生态新势能: 驱动国产 DevSecOps 与 AI 工程新进展
  • DeepSeek-R1与Claude 4.0 Sonnet:开源与闭源大模型的商业生态博弈
  • 快速生成树协议(RSTP)深度解析
  • 基于 tinyfsm 的状态机
  • 未来智能设备的三大核心能力:自检测、自修复与自决策
  • 套接字类型与协议设置
  • 微信小程序之页面跳转(路由),navigateTo redirectTo reLaunch
  • 大型语言模型的中毒攻击的系统评价
  • 一款自制的OpenMV4模块
  • 网络原理8 - HTTP协议1
  • QDialog的show()方法与exec_()方法的区别详解
  • C#.Net 使用NPOI库导出Excel(含列宽度自适应) 及 根据Excel文件生成DataTable
  • 【多智能体】基于嵌套进化算法的多代理工作流
  • 硬件学习笔记--67 接线端子压缩比相关要求
  • Python实战:高效连接与操作Elasticsearch的完整指南
  • 知名开源项目被收购,用户发现项目被“投毒”
  • 【自考】《计算机信息管理课程实验(课程代码:11393)》华师自考实践考核题型解析说明:C++ 与 mysql 实践题型与工具实践题分析
  • 火山引擎 veFuser:面向扩散模型的图像与视频生成推理服务框架
  • 机器学习四剑客:Numpy、Pandas、PIL、Matplotlib 完全指南
  • 【大模型训练】allgatherEP 过程及reduce-scatter的具体例子
  • 使用Docker申请Let‘s Encrypt证书
  • xilinx的GT配置说明(二)
  • 【HTTP重定向与缓存机制详解】
  • 芯伯乐XBLW GT712选型及应用设计指南
  • Spring Cloud业务相关问题
  • 姜伟生《统计至简》