【从零开始实现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工程

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

mongodb数据导出与导入

一、先去检查mongodump mongodump --version 如果报 mongodump version: built-without-version-string 或者其他的较老的版本&#xff0c;直接去下载最新的【传送门】 【以Ubuntu18.04为例】 安装工具 假设你下载的是 .tgz 文件&#xff08;适用于 Linux 系统&#xff09;&am…

【ARM】SMMU系统虚拟化整理

目录 1.MMU的基本介绍 1.1 特点梳理 2.功能 DVM interface PTW interface 2.1 操作流程 2.1.1 StreamID 2.1.2 安全状态&#xff1a; 2.1.3 HUM 2.1.4 可配置的操作特性 Outstanding transactions per TBU QoS 仲裁 2.2 Cache结构 2.2.1 Micro TLB 2.2.2 Macro…

昇思25天学习打卡营第23天|ResNet50图像分类

课程打卡凭证 ResNet网络 ResNet&#xff08;Residual Networks&#xff0c;残差网络&#xff09;是一种深度神经网络结构&#xff0c;它的核心思想是引入了“残差学习”来解决深度网络中的退化问题。在深度神经网络中&#xff0c;当网络层数增加到一定程度时&#xff0c;网络…

深入理解Linux网络(二):UDP接收内核探究

深入理解Linux网络&#xff08;二&#xff09;&#xff1a;UDP接收内核探究 一、UDP 协议处理二、recvfrom 系统调⽤实现 一、UDP 协议处理 udp 协议的处理函数是 udp_rcv。 //file: net/ipv4/udp.c int udp_rcv(struct sk_buff *skb) {return __udp4_lib_rcv(skb, &udp_…

什么是单例模式,有哪些应用?

目录 一、定义 二、应用场景 三、6种实现方式 1、懒汉式&#xff0c;线程不安全。 2、懒汉式&#xff0c;线程安全 3、双检锁/双重校验锁&#xff08;DCL&#xff0c;即 double-checked locking&#xff09; 4、静态内部类方式-------只适用于静态域 5、饿汉式 6、枚举…

Linux系统编程基础

Linux操作系统 Linux不是一个具体的操作系统&#xff0c;而是一类操作系统的总称&#xff0c;具体版本成为发行版。 Red Hat&#xff1a;目前被IBM收购&#xff0c;收费版&#xff0c;目前最大的Linux供应商CentOS&#xff1a; Red Hat退出的免费版Ubuntu&#xff1a;界面比较友…

【Gin】精准应用:Gin框架中工厂模式的现代软件开发策略与实施技巧(上)

【Gin】精准应用&#xff1a;Gin框架中工厂模式的现代软件开发策略与实施技巧(上) 大家好 我是寸铁&#x1f44a; 【Gin】精准应用&#xff1a;Gin框架中工厂模式的现代软件开发策略与实施技巧(上)✨ 喜欢的小伙伴可以点点关注 &#x1f49d; 前言 本次文章分为上下两部分&…

【C语言】动态内存管理(上)

文章目录 前言1.为什么要存在动态内存2. malloc和free2.1 malloc2.2 free2.3 使用实例&#xff08;malloc和free&#xff09; 3. calloc3.1 calloc例子 前言 本文开始将开始学习C语言中一个比较重要的知识点或者是操作——动态内存管理。由于本次的知识比较重要&#xff0c;为…

科技赋能,智慧粮仓视频综合管理方案助力粮食安全

一、背景需求 随着科技的快速发展&#xff0c;智慧化、智能化管理已成为各行各业的重要发展方向。粮食仓储作为国家粮食安全战略的重要组成部分&#xff0c;其管理的科学性和智能化水平直接关系到粮食的存储安全、品质保障和运营效率。 因此&#xff0c;TSINGSEE青犀提出一套…

GaussDB常见调优指南

文章目录 GaussDB常见调优指南一. Analyze 统计信息解析二. Explain 分布式计划解析三. 性能调优总体策略详解四. 性能调优之坏味道 SQL 识别五. 性能调优之好味道表定义六. 性能调优之 SQL 改写七. 性能调优之路径干预八. 性能调优之 Plan hint 运用九. 性能调优之 GUC 参数调…

Linux 12:多线程2

1. 生产者消费者模型 生产者消费者模型有三种关系&#xff0c;两个角色&#xff0c;一个交易场所。 三种关系&#xff1a; 生产者之间是什么关系?竞争 - 互斥 消费者和消费者之间?竞争 - 互斥 消费者和消费者之间?互斥和同步 两个角色&#xff1a; 生产者和消费者 一个交…

git 提交的进阶操作

cherry-pick cherry-pick 是 Git 中的一种操作,允许你从一个分支中选择特定的 commit,并将其应用到另一个分支。它的主要用途是将特定的更改引入到其他分支,而无需合并整个分支历史。这在修复 bug 或者移植某些功能时特别有用。 cherry-pick 的使用场景 Bug 修复: 例如,你…

安卓手机怎么格式化?格式化后数据如何恢复?1篇文章全搞定

随着时间的推移&#xff0c;手机中的数据越积越多&#xff0c;有时候我们可能需要对其进行一次彻底的大扫除——格式化。它就像一把双刃剑&#xff0c;一方面能够清除手机中的冗余数据&#xff0c;提升手机的运行效率&#xff1b;另一方面&#xff0c;如果不慎操作&#xff0c;…

Postman导出excel文件

0 写在前面 在我们后端写接口的时候&#xff0c;前端页面还没有出来&#xff0c;我们就得先接口测试&#xff0c;在此记录下如何使用postman测试导出excel接口。 如果不会使用接口传参可以看我这篇博客如何使用Postman 1 方法一 2 方法二 3 写在末尾 虽然在代码中写入文件名…

Apache BookKeeper 一致性协议解析

导语 Apache Pulsar 是一个多租户、高性能的服务间消息传输解决方案&#xff0c;支持多租户、低延时、读写分离、跨地域复制&#xff08;GEO replication&#xff09;、快速扩容、灵活容错等特性。Pulsar 存储层依托于 BookKeeper 组件&#xff0c;所以本文简单探讨一下 BookK…

QXlsx读写excel

QXlsx读写excel 安装 QXlsx使用 qmake使用 CMake 基本用法1. 写入 Excel 文件2. 读取 Excel 文件 详细用法1. 设置单元格样式2. 合并单元格3. 创建图表4. 设置列宽和行高 完整示例 QXlsx 是一个用于在 Qt 应用中读写 Excel 文件的第三方库。它提供了丰富的 API&#xff0c;可以…

react 快速入门思维导图

在掌握了react中一下的几个步骤和语法&#xff0c;基本上就可以熟练的使用react了。 1、组件的使用。react创建组件主要是类组件和函数式组件&#xff0c;类组件有生命周期&#xff0c;而函数式组件没有。 2、jsx语法。react主要使用jsx语法&#xff0c;需要使用babel和webpa…

由delete引起的锁扩大

这句话意思是&#xff1a;假设delete语句物理删除数据&#xff0c;那么delete事务会持有gap lock&#xff0c;那么会造成锁扩大&#xff0c;而实际上delete操作会转为update操作&#xff0c;最终delete事务持有的gap lock退化为record lock&#xff0c;不会造成锁扩大 下面用SQ…

FPGA:频闪灯设计

1、需求 若在FPGA上实现LED灯一秒闪烁一次&#xff0c;先进行计算&#xff0c;1秒闪烁一次&#xff0c;即周期为1秒&#xff0c;开发板XC7A35TFFG-2的基本时钟输入由板载 50MHz 有源晶振提供&#xff0c;即频率为f 50MHz 。 则一个周期为 T 1 f 1 50 M H z 20 n s T\frac{…

十七、【机器学习】【非监督学习】- K-均值 (K-Means)

系列文章目录 第一章 【机器学习】初识机器学习 第二章 【机器学习】【监督学习】- 逻辑回归算法 (Logistic Regression) 第三章 【机器学习】【监督学习】- 支持向量机 (SVM) 第四章【机器学习】【监督学习】- K-近邻算法 (K-NN) 第五章【机器学习】【监督学习】- 决策树…