基于DSP的三相开关霍尔永磁同步电机控制

news2024/9/26 1:25:19

0 前言

本文本应该是一篇 记录我使用DSP28377D控制一个基于三相开关霍尔传感器的高速永磁同步电机全过程的长文,但大部分零散的知识点我都已经写成单独的博客了,所以本文更像是一个知识框架的梳理。本文最终目的是实现高速PMSM的电流-速度双闭环,将电机速度控制在80r/s左右,精度越高越好。

1 硬件的理解

图1 硬件连接

如图1所示,被控对象是一个永磁同步电机,然后在永磁同步电机定子的底部,安装了三个三相对称的开关型霍尔传感器,可以用于检测电机的转速和电角度。 永磁同步电机的输入电压,是由一个型号为DRV8322DKD的驱动芯片给出的三相电压输出。该芯片主要的作用是把三相PWM输入波形,转换成三相电压输出。另外,提供便捷的测量三相电流的通道,而电流的采集是用的型号为MAX40056FAUA/V的芯片, 拿到了三相电机的电流、转速以及电角度,DSP要作为控制器需要去设计相应的控制算法,然后输出相应的三相PWM波形,形成闭环。 每当DSP输出一次PWM波形的时候,可以同时触发下一次的电流采集转换。这令电流环的实现就非常的丝滑,不得不说DSP在这点上的设计还是很好的。 

2 DSP底层外设驱动学习

对于初学DSP的人来讲,在DSP的底层驱动外设之前,一个完美的DSP28377D程序框架搭建是基础中的基础。这部分的内容在本文就不展开讲了,请参考DSP_基于TMS320F28377D双核芯片和CCS7.40的编程入门_江湖上都叫我秋博的博客-CSDN博客_tms320f28377

另外,根据图1可以总结出,要实现PMSM的速度环控制,需要掌握的DSP底层外设驱动包括三个部分,我已经把坑全部填完了,请参考下面三篇博客。

2.1 ADC模块的使用

DSP_TMS320F28377D_ADC学习笔记_江湖上都叫我秋博的博客-CSDN博客

2.2 ePWM模块的使用

DSP_TMS320F28377D_ePWM学习笔记_江湖上都叫我秋博的博客-CSDN博客

2.3 eCAP模块的使用

DSP_TMS320F28377D_eCAP学习笔记_江湖上都叫我秋博的博客-CSDN博客

如果要把DSP部分的内容扩充更详细、更丰富,对定时器的使用系统的中断配置也是需要补充的,两个部分的坑,我尽快填上。

2.4 CPU Timer模块的使用

关于定时器实现 <获取代码块运算时间>的功能,也是可以浅看一下。量化某代码段的运行时间对于一个系统而言,也是比较重要的,而不是你觉得它能在多少时间内运行完。

DSP_TMS320F28377D_使用定时器实现<获取代码块运算时间>的功能_江湖上都叫我秋博的博客-CSDN博客

当然,定时器对于控制系统而言更重要的作用,是实现系统的软分频功能。利用软分频得到的固定频率标志,可以便捷的实现控制器的离散化控制。

DSP_TMS320F28377D_CPU Timer学习笔记_江湖上都叫我秋博的博客-CSDN博客

2.5 PIE及中断模块的使用

DSP中的很多模块(例如ADC、eCAP、CPU Timer)都需要使用中断,因此中断配置的学习也是一个必不可少的基础知识,下面还需要填个坑。

3 永磁同步电机控制

在学习了必要的DSP基础知识之后,更多的重心就要放到控制相关的内容,与控制相关的内容可以大概分为5个部分,传感器的标定与解算、永磁同步电机的FOC控制、被控对象系统辨识、电流环与速度环的PI控制器设计、控制精度优化。下面将会展开讲本人对于这5个部分内容的理解。

3.1 传感器的标定与解算

对于本文所涉及的三相开关霍尔永磁同步电机,它包含的传感器主要有两个,一个是三相开关霍尔,一个是电流采集传感器(或芯片)。

3.1.1三相开关霍尔

三相开关霍尔用于获取电机的电角度与电机的机械转速,对于这部分知识,我也单独写了一篇博客。

传感器_三相-双极性-开关型-霍尔传感器 速度+电角度解算理解_开关型霍尔传感器_江湖上都叫我秋博的博客-CSDN博客

这篇博客写的还有点瑕疵,我再补充一下我的标定办法。

3.1.2电流采集

关于电路采集传感器,是用电流采集芯片。此系统使用该芯片采集了电机ia和ib的两相电流。

关于电流采集芯片的使用,碰巧在之前的工作中也记录了,参考下面这篇博客。

STM32_ADC模块及针对芯片MAX40056FAUA/V+的使用_江湖上都叫我秋博的博客-CSDN博客

为什么系统只采集电机的ia和ib两相的电流,不采集ic呢?我也在另一篇博客中写了一些我自己的理解。

STM32_FOC_1_Clarke变换计算iα和iβ为何仅用ia ib两相电流_αβ变换电压电流_江湖上都叫我秋博的博客-CSDN博客

下面在补充一下去零偏的方法。

3.2 永磁同步电机的FOC控制

对于初学者学习FOC控制来讲,华为的天才少年稚晖君写了一篇很好的文章,值得反复阅读。

【自制FOC驱动器】深入浅出讲解FOC算法与SVPWM技术 - 知乎 (zhihu.com)

本人对FOC的理解很浅,直接贴电流环开环代码做个备份,感兴趣的朋友也可以借鉴一下,老鸟朋友如果看出有什么问题,也希望你们不要吝啬给我指出(评论或者私信都可以哟)。

void currentopenloop(void){

    float TempVar1 = 0.0f;
    float TempVar2 = 0.0f;
    
    theta = getElecAngle1();
    sin_theta = __sin(theta);
    cos_theta = __cos(theta);

    // Anti-Park
    V_Alpha   = (id*cos_theta - iq*sin_theta);
    V_Beta    = (id*sin_theta + iq*cos_theta);

    // 确定扇区
    TempVar1 = V_Alpha * 0.86602540378444f;
    TempVar2 = V_Beta * 0.5f;

    SectorJudgmentFactor1 =   TempVar1 - TempVar2;
    SectorJudgmentFactor2 = - TempVar1 - TempVar2;

    SectorNum = 0;
    if( V_Beta >= 0)
        SectorNum = SectorNum + 1;
    if( SectorJudgmentFactor1 >= 0 )
        SectorNum = SectorNum + 2;
    if( SectorJudgmentFactor2 >= 0 )
        SectorNum = SectorNum + 4;

    // 计算中间变量X Y Z
    MiddleTerm_X    = V_Beta;
    MiddleTerm_Y    = TempVar1 + TempVar2;
    MiddleTerm_Z    = -TempVar1 + TempVar2;

    // ? where is √3*Ts/Vdc ?

    // 作用时间计算
    switch(SectorNum){
        case 0:
            t_cm1 = 0;
            t_cm2 = 0;
            t_cm3 = 0;
            break;
        case 1:   /*Sector 1: t_1st = Z     and t_2nd = Y       (Tcm1/2/3 ---> Tb,Ta,Tc)*/
            t_first     = MiddleTerm_Z;
            t_second    = MiddleTerm_Y;

            //  过调制处理
            if(t_first + t_second > 1){
                t_firstaddsecond    = t_first + t_second;
                t_first             = __divf32(t_first,t_firstaddsecond);
                t_second            = __divf32(t_second,t_firstaddsecond);
            }

            t_a = (1 - t_first - t_second) * 0.5;      // ? why not (Ts - t_first - t_second) / 4
            t_b = t_a + t_first;
            t_c = t_b + t_second;

            t_cm1   = t_b;
            t_cm2   = t_a;
            t_cm3   = t_c;
            break;
        case 2:   /*Sector 2: t_1st = Y     and t_2nd = -X  (Tcm1/2/3 ---> Ta,Tc,Tb)*/
            t_first     = MiddleTerm_Y;
            t_second    = -MiddleTerm_X;
            //  过调制处理
            if(t_first + t_second > 1){
                t_firstaddsecond    = t_first + t_second;
                t_first             = __divf32(t_first,t_firstaddsecond);
                t_second            = __divf32(t_second,t_firstaddsecond);
            }
            t_a = (1 - t_first - t_second) * 0.5;      // ? why not (Ts - t_first - t_second) / 4
            t_b = t_a + t_first;
            t_c = t_b + t_second;
            t_cm1   = t_a;
            t_cm2   = t_c;
            t_cm3   = t_b;
            break;
        case 3:   /*Sector 3: t_1st = -Z    and t_2nd = X       (Tcm1/2/3 ---> Ta,Tb,Tc)*/
            t_first     = -MiddleTerm_Z;
            t_second    = MiddleTerm_X;

            //  过调制处理
            if(t_first + t_second > 1){
                t_firstaddsecond    = t_first + t_second;
                t_first             = __divf32(t_first,t_firstaddsecond);
                t_second            = __divf32(t_second,t_firstaddsecond);
            }

            t_a = (1 - t_first - t_second) * 0.5;      // ? why not (Ts - t_first - t_second) / 4
            t_b = t_a + t_first;
            t_c = t_b + t_second;
            t_cm1   = t_a;
            t_cm2   = t_b;
            t_cm3   = t_c;
            break;
        case 4:   /*Sector 4: t_1st = -X    and t_2nd = Z       (Tcm1/2/3 ---> Tc,Tb,Ta)*/
            t_first     = -MiddleTerm_X;
            t_second    = MiddleTerm_Z;
            //  过调制处理
            if(t_first + t_second > 1){
                t_firstaddsecond    = t_first + t_second;
                t_first             = __divf32(t_first,t_firstaddsecond);
                t_second            = __divf32(t_second,t_firstaddsecond);
            }
            t_a = (1 - t_first - t_second) * 0.5;      // ? why not (Ts - t_first - t_second) / 4
            t_b = t_a + t_first;
            t_c = t_b + t_second;
            t_cm1   = t_c;
            t_cm2   = t_b;
            t_cm3   = t_a;
            break;
        case 5:   /*Sector 5: t_1st = X     and t_2nd = -Y  (Tcm1/2/3 ---> Tc,Ta,Tb)*/
            t_first     = MiddleTerm_X;
            t_second    = -MiddleTerm_Y;
            //  过调制处理
            if(t_first + t_second >= 1){
                t_firstaddsecond    = t_first + t_second;
                t_first             = __divf32(t_first,t_firstaddsecond);
                t_second            = __divf32(t_second,t_firstaddsecond);
            }
            t_a = (1 - t_first - t_second) * 0.5;      // ? why not (Ts - t_first - t_second) / 4
            t_b = t_a + t_first;
            t_c = t_b + t_second;
            t_cm1   = t_c;
            t_cm2   = t_a;
            t_cm3   = t_b;
            break;
        case 6:   /*Sector 6: t_1st = -Y    and t_2nd = -Z  (Tcm1/2/3 ---> Tb,Tc,Ta)*/
            t_first     = -MiddleTerm_Y;
            t_second    = -MiddleTerm_Z;
            //  过调制处理
            if(t_first + t_second >= 1){
                t_firstaddsecond    = t_first + t_second;
                t_first             = __divf32(t_first,t_firstaddsecond);
                t_second            = __divf32(t_second,t_firstaddsecond);
            }
            t_a = (1 - t_first - t_second) * 0.5;      // ? why not (Ts - t_first - t_second) / 4
            t_b = t_a + t_first;
            t_c = t_b + t_second;
            t_cm1   = t_b;
            t_cm2   = t_c;
            t_cm3   = t_a;
            break;

        default:
            break;
    }

    EPwm1Regs.CMPA.bit.CMPA    =   (Uint16)(t_cm1*EPWM1_TIMER_TBPRD);
    EPwm2Regs.CMPA.bit.CMPA    =   (Uint16)(t_cm2*EPWM2_TIMER_TBPRD);
    EPwm3Regs.CMPA.bit.CMPA    =   (Uint16)(t_cm3*EPWM3_TIMER_TBPRD);
}

3.3 被控对象系统辨识

谈起被控对象辨识,简直说多了都是泪啊,这个控制系统竟然没有留和上位机的通信接口,我以前写过一个基于串口通信的控制调试软件,里面就包含了系统辨识的功能,而且是集美貌与才华于一身的软件,我还给她取了一个名字:Angela。Angela就像我的女儿一样,必须给大家介绍一下。

Angela运行视频

Angela不仅支持DSP,她还有一个同卵双胞胎AngelaS(支持在STM32平台上使用),AngelaS用到的核心技术之一可以参考STM32_上位机高效通信技术_stm32用v9如何使用上位机_江湖上都叫我秋博的博客-CSDN博客。

好了,收!别过度沉迷Angela,安利结束。 回过头来,我们还需要面对现实。得益于CCS强大的功能,虽然DSP没有留和上位机的通信接口,但是我们仍然可以实现无通信接口系统辨识。详情请看如下三篇博客。

DSP_CCS7实现变量的导出与MatLAB读取_ccs怎么导出数组数据_江湖上都叫我秋博的博客-CSDN博客

DSP_定义一个大的全局数组_探索之路_江湖上都叫我秋博的博客-CSDN博客

DSP_无通信接口系统辨识_江湖上都叫我秋博的博客-CSDN博客

3.4 电流环与速度环的PI控制器设计

辨识完了被控对象,设计控制器还不是轻轻松松,本小节的内容,并不会告诉大家PI参数怎么整定(这个我也不会),但是我会告诉大家一个利用MatLAB设计PI控制器的小技巧。这东西还是有点妙的。

在我们辨识得到的被控对象之后

 可以利用sisotool把辨识得到的被控对象导入

 导入被控对象后,就可以自动整定PI参数

 使用上诉提到的方法得到PI控制器,基本的闭环控制一般都没问题,包括id iq电流环、速度环。但是要想得到更好的精度,那就需要微调和各种优化了。

3.5 控制精度优化

由于三相开关霍尔所得到的电角度分辨率太低!(真的是低得扣脚了),另外我对FOC的电流环、速度环优化控制方法学习不够,所以速度环闭环精度总是达不到理想的效果,为了达到更好的速度环闭环精度,我调了接近两周的控制参数。下面总结一下我认为有效的优化方法。

1、优化电角度估计(匀速模型)

2、电流环不加惯性环节

3、id、iq添加前馈去耦合(但各参数我都不知道,就瞎调了几个参数)

×

4、ia、ib、ic、id、iq添加低通滤波(我做实验是真的没效果)

×

5、提高电流环开环执行频率(有提升,但不大)

6、ia ib的电流采集使用多通道,然后取均值的方式

×

7、ia ib的电流解算的偏置量,使用取前1000个电机不运行数据的均值

×

8、电流环的控制器设计成二阶(两个积分环节)

×

各位大佬有什么好的文献或者优化思路,望不吝赐教,评论区|私信 走起。

4 结束语

放个电机的运行视频吧,精度还不够,大家看个热闹吧

PMSM运行视频

另外,前面内容需要填的坑,我会尽快填上的。

愿我们共同进步! 感谢您的阅读,欢迎留言讨论、收藏、点赞、分享。

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

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

相关文章

[LK光流法,disflow using Dense Inverse Search, VariationalRefinement变分优化 原理和代码]

文章目录1.Fast Optical Flow using Dense Inverse Search1.1 W的含义&#xff1a;1.2 LK光流模型1.3 LK光流模型求解&#xff08;不含迭代&#xff09;1.4 LK光流模型迭代求解1.5 dis_flow方法中的 LK光流模型1.6 disflow代码分析2.0 disflow中的VariationalRefinement方法2.0…

大佬们都说tcp有黏包的问题,tcp却说:我冤枉!

相关参考添加链接描述 相关参考 什么是tcp TCP,全称Transmission Control Protocol&#xff0c;是一种传输控制协议&#xff0c;TCP协议也是计算机网络中非常复杂的一个协议 tcp的特点 tcp是面向连接的协议tcp是端到端的链接tcp提供可靠的传输服务tcp协议提供双工通信tcp是…

【计算机考研408】快速排序的趟数问题 + PAT 甲级 7-2 The Second Run of Quicksort

前言 该题还未加入PAT甲级题库中&#xff0c;可以通过购买2022年秋季甲级考试进行答题&#xff0c;纯考研题改编 快速排序 常考的知识点 快速排序是基于分治法快速排序是所有内部排序算法中平均性能最优的排序算法快速排序是一种不稳定的排序算法快速排序算法中&#xff0c…

异步Buck和同步Buck的特点

1 介绍 随着时代的发展&#xff0c;工业&#xff0c;车载&#xff0c;通信&#xff0c;消费类等产品都提出了小型化&#xff0c;智能化的需求。相应的&#xff0c;对于这些系统中的电源模块提出了小型化的要求。目前&#xff0c;市场上依然存在很多异步Buck电源管理芯片使用的场…

atomic 原子操作

atomic 原子操作前言atomic_t定义内核中的实现armv7的实现armv8的实现Exclusive monitor实现所处的位置External exclusive monitorAtomic指令的支持QA前言 修改一个变量会经过读、修改、写的操作序列。但有时该操作序列在执行完毕前会被其他任务或事件打断。 比如在多CPU体系…

python基础学习3--切片(slice)

在python中&#xff0c;切片&#xff08;slice&#xff09;是对序列型对象&#xff08;如list,string,tuple)的一种高级索引方法。普通索引只取出序列一个下标对应的元素&#xff0c;而切片取出序列中一个范围对应的元素&#xff0c;这里的范围不是狭义上的连续片段。通俗一点就…

CLion Debug 调试 Makefile 构建的 C 语言程序断点不起作用

最近在研究 jattach&#xff0c;打算在本地调试项目&#xff0c;发现 CLion 可以正常编译运行代码&#xff0c;却无法断点 Debug。由于笔者对 C/C 项目不熟悉&#xff0c;在此记录研究过程中遇到的一些基本问题与解决方法。 文章目录解决方式尝试过的手段【未解决】找 Native D…

RIG Exploit Kit 仍然通过 IE 感染企业用户

RIG Exploit Kit 正处于最成功的时期&#xff0c;每天尝试大约 2000 次入侵并在大约 30% 的案例中成功&#xff0c;这是该服务长期运行历史中的最高比率。 通过利用相对较旧的 Internet Explorer 漏洞&#xff0c;RIG EK 已被发现分发各种恶意软件系列&#xff0c;包括 Dridex…

内科大机器学习期末重点

1. 什么是机器学习 &#xff08;由于图床原因导致部分图片错位&#xff0c;可以借鉴着看&#xff09; 语音识别算法推荐人脸识别垃圾邮件过滤贷款资格审核 2. 学习的概念 与经验有关 学习可以改善系统性能 学习是一个有反馈的信息处理与控制过程 3. 学习分类&#xff1a…

996的压力下,程序员还有时间做副业吗?

996怎么搞副业&#xff1f; 这个问题其实蛮奇怪的&#xff1a;996的压力下&#xff0c;怎么会还想着搞副业呢&#xff1f; 996还想搞副业的原因有哪些&#xff1f; 大家对于996应该都不陌生&#xff0c;总结就是一个字&#xff1a;忙。 996的工作性质就是加班&#xff0c;就…

基于龙芯+国产FPGA 的VPX以太网交换板设计(二)

3.1 板卡技术要求 3.1.1 主要性能指标 本着向下兼容的原则&#xff0c;以太网交换板的设计尽量保留传统信息处理平台的基本功 能和接口&#xff0c;重点考虑提升设备的性能和扩展性。本课题以太网交换板的主要性能指标 如下&#xff1a; &#xff08;1&#xff09; 具有大容量无…

一文搞懂华为防火墙的原理和配置

“防火墙”一词起源于建筑领域&#xff0c;用来隔离火灾&#xff0c;阻止火势从一个区域蔓延到另一个区域。引入到通信领域&#xff0c;防火墙这一具体设备通常用于两个网络之间有针对性的、逻辑意义上的隔离。这种隔离是选择性的&#xff0c;隔离“火”的蔓延&#xff0c;而又…

mac安装docker hub及使用

1. docker hub安装 官网&#xff1a;Docker https://hub.docker.com/ 去官网 下载 Docker.dmg 并安装 2. docker hub的使用 step1: 首先克隆一个仓库 Getting Started 项目是一个简单的Github仓库&#xff0c;他包含了你创建镜像的所有东西&#xff0c;并且可以把他当容…

文心一言的蝴蝶振翅,云计算的飓风狂飙

ChatGPT带来的多米诺效应正在不断涌现。社会各界都在关注一系列问题&#xff0c;比如中国版ChatGPT什么时候能来到&#xff1f;其效果如何&#xff1f;类ChatGPT应用的投资与创业前景会怎样&#xff1f;相关产品能带来哪些应用价值&#xff1f;随着百度文心一言等产品相继官宣&…

面试问题【数据库】

数据库数据库的三范式是什么drop、delete、truncate 分别在什么场景之下使用char 和 varchar 的区别是什么数据库的乐观锁和悲观锁是什么SQL 约束有哪几种mysql 的内连接、左连接、右连接有什么区别MyIASM和Innodb两种引擎所使用的索引的数据结构是什么mysql 有关权限的表都有哪…

SpringSecurity常见面试题汇总(超详细回答)

1.什么是Spring Security&#xff1f;核心功能&#xff1f;Spring Security是一个基于Spring框架的安全框架&#xff0c;提供了完整的安全解决方案&#xff0c;包括认证、授权、攻击防护等功能。其核心功能包括&#xff1a;认证&#xff1a;提供了多种认证方式&#xff0c;如表…

线性表 链表表示

初识链表 用一组物理位置任意的存储单元来存放线性表的数据元素。这组存储单元既可以是连续的&#xff0c;也可以是不连续的&#xff0c;甚至是零散分布在内存中的任意位置上的。链表中元素的逻辑次序和物理次序不一定相同。 在存储自己内容的同时也存储下一个元素的地址。存…

Adobe illustrator使用教程

抓手工具&#xff1a;绘制大型图片拖动图片 画放大缩小&#xff1a;Alt鼠标滚轮 间接选择工具&#xff1a;点击图标shift 进行多个对象选择&#xff0c;再次点击取消选择&#xff08;用于对多个对象进行批量操作&#xff09; 直接选择工具&#xff1a;可以对图案本身进行精细选…

(二十二)操作系统-生产者·消费者问题

文章目录一、问题描述二、问题分析三、PV操作题目分析步骤1. 关系分析2. 整理思路3. 设置信号量4. 编写代码四、能否改变相邻P、V操作的顺序?五、小结1. PV操作题目的解题思路2. 注一、问题描述 系统中有一组生产者进程和一组消费者进程&#xff0c;生产者进程每次生产一个产品…

什么是文件传输中台?

企业文件传输的场景有哪些&#xff1f; 企业日常办公中无时无刻不在产生数据文件。多样化的数据已成为企业的重要资产&#xff0c;更被称为是“新石油”。数据并不是单单存储起来就行了&#xff0c;而是需要高效又安全的让数据流转起来&#xff0c;释放其自身的价值&#xff0…