【从零开始实现stm32无刷电机FOC】【实践】【6/7 CMSIS-DSP】

目录

  • 导入CMSIS-DSP库
  • 使用CMSIS-DSP

点击查看本文开源的完整FOC工程
CMSIS-DSP库是ARM开源的、对ARM处理器优化的数学库,本文使用了其提供的三角函数、反park变换函数、park变换函数、clarke变换函数、PID控制器。
CMSIS-DSP原始代码仓库是https://github.com/ARM-software/CMSIS-DSP,官方对其的介绍是一个针对Cortex-M和Cortex-A内核优化的嵌入式系统计算库,此处的DSP不是指的硬件,而是数字处理的意思。
在这里插入图片描述

导入CMSIS-DSP库

本文使用stm32cube编译好的CMSIS-DSP二进制文件,首先在Middleware and Software Packs中选择X-CUBE-ALGOBUILD:在这里插入图片描述
选择安装DSP Library,并且勾选Selection,下图为已经安装好的状态:
在这里插入图片描述
勾选DSP Library Library:
在这里插入图片描述
到此,工程代码里就能够使用CMSIS-DSP库了,只需在要使用DSP库的C源文件加上

#include "arm_math.h"

使用CMSIS-DSP

三角函数:
单独计算sin和cos三角函数,输入弧度rad:

  float32_t arm_sin_f32(float32_t x);float32_t arm_cos_f32(float32_t x);

单个函数完成计算sin和cos三角函数,输入角度deg:

  /*** @brief  Floating-point sin_cos function.* @param[in]  theta   input value in degrees* @param[out] pSinVal  points to the processed sine output.* @param[out] pCosVal  points to the processed cos output.*/void arm_sin_cos_f32(float32_t theta,float32_t * pSinVal,float32_t * pCosVal);

clarke变换:

  /**** @brief  Floating-point Clarke transform* @param[in]  Ia       input three-phase coordinate <code>a</code>* @param[in]  Ib       input three-phase coordinate <code>b</code>* @param[out] pIalpha  points to output two-phase orthogonal vector axis alpha* @param[out] pIbeta   points to output two-phase orthogonal vector axis beta* @return        none*/__STATIC_FORCEINLINE void arm_clarke_f32(float32_t Ia,float32_t Ib,float32_t * pIalpha,float32_t * pIbeta)

clarke变换是将三个相线电流投影到 α \alpha α β \beta β轴,由于三个相线电流相加等于0,因此只需要输入两个相线电流IaIb到clarke变换函数中,输出到pIalphapIbeta

park变换:

  /*** @brief Floating-point Park transform* @param[in]  Ialpha  input two-phase vector coordinate alpha* @param[in]  Ibeta   input two-phase vector coordinate beta* @param[out] pId     points to output   rotor reference frame d* @param[out] pIq     points to output   rotor reference frame q* @param[in]  sinVal  sine value of rotation angle theta* @param[in]  cosVal  cosine value of rotation angle theta* @return     none** The function implements the forward Park transform.**/__STATIC_FORCEINLINE void arm_park_f32(float32_t Ialpha,float32_t Ibeta,float32_t * pId,float32_t * pIq,float32_t sinVal,float32_t cosVal)

park变换是将 α \alpha α β \beta β轴投影到dq轴,此处的sinValcosVal为转子角度的sin和cos值。

反park变换:

   /*** @brief  Floating-point Inverse Park transform* @param[in]  Id       input coordinate of rotor reference frame d* @param[in]  Iq       input coordinate of rotor reference frame q* @param[out] pIalpha  points to output two-phase orthogonal vector axis alpha* @param[out] pIbeta   points to output two-phase orthogonal vector axis beta* @param[in]  sinVal   sine value of rotation angle theta* @param[in]  cosVal   cosine value of rotation angle theta* @return     none*/__STATIC_FORCEINLINE void arm_inv_park_f32(float32_t Id,float32_t Iq,float32_t * pIalpha,float32_t * pIbeta,float32_t sinVal,float32_t cosVal)

反park变换是将dq轴投影到 α \alpha α β \beta β轴,此处的sinValcosVal为转子角度的sin和cos值。

PID控制器:
CMSIS-DSP库中的PID控制器是增量式PID。
位置式PID就是直观地分别将P、I、D控制器的各自输出加起来:
u ( t ) = K p e ( t ) + K i ∑ i = 0 t ( e ( i ) ∗ Δ T ) + K d [ e ( t ) − e ( t − 1 ) ] Δ T u(t) = K_p e(t) + K_i \sum_{i=0}^{t} (e(i)*\Delta T) + K_d \frac{[e(t) - e(t-1)]} {\Delta T} u(t)=Kpe(t)+Kii=0t(e(i)ΔT)+KdΔT[e(t)e(t1)]
为了方便计算,这里将 Δ T \Delta T ΔT当作为1,在 K i K_i Ki K d K_d Kd系数上缩放回去就好了。
增量式PID理念是将PID的输出是上次PID输出的基础上加上之前两次的累计误差:
u ( t ) = u ( t − 1 ) + Δ u ( t ) u(t) =u(t-1) +\Delta u(t) u(t)=u(t1)+Δu(t)
Δ u ( t ) = u ( t ) − u ( t − 1 ) = K p e ( t ) + K i ∑ i = 0 t e ( i ) + K d [ e ( t ) − e ( t − 1 ) ] − ( K p e ( t − 1 ) + K i ∑ i = 0 t − 1 e ( i ) + K d [ e ( t − 1 ) − e ( t − 2 ) ] ) = K p [ e ( t ) − e ( t − 1 ) ] + K i e ( t ) + K d [ e ( t ) − 2 e ( t − 1 ) + e ( t − 2 ) ] = A 0 ⋅ e [ n ] + A 1 ⋅ e [ n − 1 ] + A 2 ⋅ e [ n − 2 ] 其中 { A 0 = K p + K i + K d A 1 = − K p − 2 K d A 2 = K d \Delta u(t) =u(t) -u(t-1)= K_p e(t) + K_i \sum_{i=0}^{t} e(i) + K_d [e(t) - e(t-1)]\\ -(K_p e(t-1) + K_i \sum_{i=0}^{t-1} e(i) + K_d [e(t-1) - e(t-2)])\\ = K_p [e(t) - e(t-1)] + K_i e(t) + K_d [e(t) - 2e(t-1) + e(t-2)]\\ = A_0⋅e[n]+A_1⋅e[n−1]+A_2⋅e[n−2]\\ 其中 \begin{cases} A_0=K_p+K_i+K_d\\ A_1=-K_p-2K_d\\ A_2=K_d \end{cases} Δu(t)=u(t)u(t1)=Kpe(t)+Kii=0te(i)+Kd[e(t)e(t1)](Kpe(t1)+Kii=0t1e(i)+Kd[e(t1)e(t2)])=Kp[e(t)e(t1)]+Kie(t)+Kd[e(t)2e(t1)+e(t2)]=A0e[n]+A1e[n1]+A2e[n2]其中 A0=Kp+Ki+KdA1=Kp2KdA2=Kd
A 0 , A 1 , A 2 ,本次误差 e [ n ] ,上次误差 e [ n − 1 ] ,上上次误差 e [ n − 2 ] ,上一次的 P I D 输出 u ( t − 1 ) A_0,A_1,A_2,本次误差e[n],上次误差e[n-1],上上次误差e[n-2],上一次的PID输出u(t-1) A0A1A2,本次误差e[n],上次误差e[n1],上上次误差e[n2],上一次的PID输出u(t1)均为已知数,增量式PID的输出 u ( t ) u(t) u(t)也就能够计算出来了。
从增量式PID公式 Δ u ( t ) = K p [ e ( t ) − e ( t − 1 ) ] + K i e ( t ) + K d [ e ( t ) − 2 e ( t − 1 ) + e ( t − 2 ) ] \Delta u(t) = K_p [e(t) - e(t-1)] + K_i e(t) + K_d [e(t) - 2e(t-1) + e(t-2)] Δu(t)=Kp[e(t)e(t1)]+Kie(t)+Kd[e(t)2e(t1)+e(t2)]可以看出,当被控参数突然受到大的扰动时,不像位置式PID的P项 K p ∗ e ( t ) K_p*e(t) Kpe(t)会产生一个大的输出,增量式PID的 K p [ e ( t ) − e ( t − 1 ) ] K_p [e(t) - e(t-1)] Kp[e(t)e(t1)]输出是不大的,因此增量式PID对被控参数变化的输出比较平滑,不会突变,当然响应没有位置式PID快。
在代码上,首先需要创建一个PID控制器:

arm_pid_instance_f32 pid_position;

然后设置PID控制器的PID参数:

pid_position.Kp = 1.2;
pid_position.Ki = 0.01;
pid_position.Kd = 2.1;

然后调用函数初始化PID控制器:

/*** @brief  Initialization function for the floating-point PID Control.* @param[in,out] *S points to an instance of the PID structure.* @param[in]     resetStateFlag  flag to reset the state. 0 = no change in state & 1 = reset the state.* @return none.* \par Description:* \par* The <code>resetStateFlag</code> specifies whether to set state to zero or not. \n* The function computes the structure fields: <code>A0</code>, <code>A1</code> <code>A2</code>* using the proportional gain( \c Kp), integral gain( \c Ki) and derivative gain( \c Kd)* also sets the state variables to all zeros.*/void arm_pid_init_f32(arm_pid_instance_f32 * S,int32_t resetStateFlag)

其中参数resetStateFlag为0时,会清空PID控制器内部保存的增量式数据: e [ n ] , e [ n − 1 ] , e [ n − 2 ] e[n],e[n-1],e[n-2] e[n],e[n1],e[n2]
一般初始化的用法是:

arm_pid_init_f32(&pid_position, false);

此时就能够调用函数计算PID输出值了:

  /*** @brief         Process function for the floating-point PID Control.* @param[in,out] S   is an instance of the floating-point PID Control structure* @param[in]     in  input sample to process* @return        processed output sample.*/__STATIC_FORCEINLINE float32_t arm_pid_f32(arm_pid_instance_f32 * S,float32_t in)

其中参数S是PID控制器,参数in是被控参数的差值,返回PID控制器的输出值。


至此,所有准备工作就绪,我们了解了理论推导、FOC特定外设的配置和数学库的使用,接下来进入从零开始实现stm32无刷电机FOC工程代码讲解。
点击查看本文开源的完整FOC工程

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

双领域TOP10优秀安全企业!通付盾入选《嘶吼2024网络安全产业图谱》六大分类14项细分领域

7月16日&#xff0c;嘶吼安全产业研究院正式发布《嘶吼2024网络安全产业图谱》&#xff08;以下简称“图谱”&#xff09;&#xff0c;通过市场调研、数据精析、文献研究及政策参考等多方面的综合分析&#xff0c;全面展示网络安全产业的构成及其重要组成部分&#xff0c;探索网…

MongoDB教程(九):java集成mongoDB

&#x1f49d;&#x1f49d;&#x1f49d;首先&#xff0c;欢迎各位来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里不仅可以有所收获&#xff0c;同时也能感受到一份轻松欢乐的氛围&#xff0c;祝你生活愉快&#xff01; 文章目录 引言一、环境准…

网安小贴士(19)入侵检测技术原理与应用

前言 入侵检测技术&#xff08;Intrusion Detection System, 简称IDS&#xff09;是一种用于监测和防止计算机网络中的恶意活动的安全系统。它通过收集系统状态信息、特征提取、建立模型、入侵检测以及反馈更新等步骤&#xff0c;及时检测网络和系统中可能遭受攻击的迹象并发出…

python安装talib库教程

【talib介绍】 Talib介绍 Talib&#xff0c;全称“Technical Analysis Library”&#xff0c;即技术分析库&#xff0c;是一个广泛应用于金融量化领域的Python库。该库由C语言编写&#xff0c;支持Python调用&#xff0c;为投资者、交易员和数据分析师提供了强大的技术分析工…

借力Jersey,铸就卓越RESTful API体验

目录 maven 创建 jersey 项目 运行 支持返回 json 数据对象 1. 引言 在当今数字化时代&#xff0c;API&#xff08;应用程序编程接口&#xff09;已成为连接不同软件系统和服务的桥梁。RESTful API以其简洁、轻量级和易于理解的特点&#xff0c;成为了API设计的首选标准。本…

达梦数据库的系统视图v$arch_file

达梦数据库的系统视图v$arch_file 在达梦数据库中&#xff0c;V$ARCH_FILE 是一个动态性能视图&#xff0c;用于显示当前数据库的归档日志文件信息。这个视图可以帮助数据库管理员监控和管理归档日志文件&#xff0c;确保数据库的备份和恢复过程顺利进行。 查询本地归档日志信…

golang 基础 泛型编程

&#xff08;一&#xff09; 示例1 package _caseimport "fmt"// 定义用户类型的结构体 type user struct {ID int64Name stringAge uint8 }// 定义地址类型的结构体 type address struct {ID intProvince stringCity string }// 集合转列表函数&#…

springboot框架的事务功能

事务回顾 概念 事务是一组操作集合&#xff0c;它是一个不可分割的工作单位&#xff0c;这些操作要么同时成功&#xff0c;要么同时失败。 操作 开启事务~&#xff08;一组操作开始前&#xff0c;开启事务&#xff09;&#xff1a;start transaction / begin; 提交事务~&am…

【python基础】基本数据类型

文章目录 一. Python基本数据类型1. 整数1.1. python的四种进制1.2. 数中的下划线 2. 浮点数3. 复数4. 布尔型5. 运算符5.1. 算术运算符5.2. 比较运算符5.3. 逻辑运算符5.4 运算符优先级 6. 常量 二. 注释三. Python之禅 一. Python基本数据类型 1. 整数 无长度限制&#xff1…

【HTML入门】第十四课 - form表单(下)表单控件们(一)

上一节&#xff0c;我们学习了基本的 form 标签的属性们&#xff0c;我们说过&#xff0c;form表单是一个区域&#xff0c;里面有一些控件元素&#xff0c;这一小节&#xff0c;我们来看一下这些控件们。 目录 1 文本输入框 2 密码输入框 3 数值型输入框 4 文本域输入框 1…

如何为游戏本地化选择语言

为游戏本地化选择合适的语言是一个至关重要的决定&#xff0c;它会极大地影响您的游戏在国际市场上的成功。适当本地化的游戏可以接触到更广泛的受众&#xff0c;提高玩家满意度&#xff0c;并促进销售。以下是在决定将游戏本地化为哪种语言时需要考虑的一些关键因素&#xff1…

Java(二十一)---栈的使用和模拟实现

文章目录 前言1.什么是栈(Stack)?2. 栈的模拟实现3.stack的使用![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/80c82d22f3ee49cfaa2915d1c961573e.png)4.关于栈的oj题4.1.有效的括号4.2.逆波兰表达式4.3.栈的压入、弹出序列4.4.最小栈 前言 前面几篇我们学习了顺序…

UE4-打包游戏,游戏模式,默认关卡

一.打包游戏 注意windows系统无法打包苹果系统的执行包&#xff0c;只能使用苹果系统打包。 打包完之后是一个.exe文件。 打包要点&#xff1a; 1.确定好要操控的角色和生成位置。 2.设置默认加载的关卡和游戏模式。 在这个界面可以配置游戏的默认地图和游戏的模式&#xff0c;…

八,九、 MyBatis 操作数据库 ★ ✔

八&#xff0c;九、 MyBatis 操作数据库 JDBC 操作⽰例回顾1. 什么是MyBatis?2. MyBatis⼊⻔2.1 准备⼯作2.1.1 创建⼯程 2.1.2 数据准备2.2 配置数据库连接字符串2.3 写持久层代码 ★2.4 单元测试 ★ 使⽤Idea ⾃动⽣成测试类3. MyBatis的基础操作3.1 打印⽇志 ★3.2 参数传递…

26.js事件

事件&#xff1a;用户行为 事件三要素: 事件源 事件类型 事件处理函数 事件绑定 语法1&#xff1a;dom 0级&#xff08;dom 0级指最原始的&#xff0c;在dom标准被正式定义之前的事件处理方式&#xff0c;事件处理函数通常在<script>标签中或直接在HTML元素的事件属性上…

轻量级文本编辑器 | Notepad-- v2.17 官方版

软件简介 Notepad--是一款国产的跨平台轻量级文本编辑器&#xff0c;旨在作为 Notepad 的替代品。它使用 C 编写&#xff0c;支持 Windows、Mac、Linux 等多种操作系统。 鉴于某些Notepad竞品作者的不当言论&#xff0c;Notepad--的意义在于&#xff1a;减少一点错误言论&…

应用最优化方法及MATLAB实现——第5章代码实现

一、概述 继上一章代码后&#xff0c;这篇主要是针对于第5章代码的实现。部分代码有更改&#xff0c;会在下面说明&#xff0c;程序运行结果跟书中不完全一样&#xff0c;因为部分参数&#xff0c;书中并没有给出其在运行时设置的值&#xff0c;所以我根据我自己的调试进行了设…

SwiftUI 6.0(Xcode 16)新 PreviewModifier 协议让预览调试如虎添翼

概览 用 SwiftUI 框架开发过应用的小伙伴们都知道&#xff0c;SwiftUI 中的视图由各种属性和绑定“扑朔迷离”的缠绕在一起&#xff0c;自成体系。 想要在 Xcode 预览中泰然处之的调试 SwiftUI 视图有时并不是件容易的事。其中&#xff0c;最让人秃头码农们头疼的恐怕就要数如…

httpx,一个网络请求的 Python 新宠儿

大家好&#xff01;我是爱摸鱼的小鸿&#xff0c;关注我&#xff0c;收看每期的编程干货。 一个简单的库&#xff0c;也许能够开启我们的智慧之门&#xff0c; 一个普通的方法&#xff0c;也许能在危急时刻挽救我们于水深火热&#xff0c; 一个新颖的思维方式&#xff0c;也许能…

SpringBoot框架学习笔记(三):Lombok 和 Spring Initailizr

1 Lombok 1.1 Lombok 介绍 &#xff08;1&#xff09;Lombok 作用 简化JavaBean开发&#xff0c;可以使用Lombok的注解让代码更加简洁Java项目中&#xff0c;很多没有技术含量又必须存在的代码&#xff1a;POJO的getter/setter/toString&#xff1b;异常处理&#xff1b;I/O…