打印
[LKS32 硬件]

03. 连接BLDC电机并驱动

[复制链接]
1665|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 北方西门吹雪 于 2022-7-7 15:05 编辑

#申请原创# 1. 下载器的花式选择。最近PowerWriter搞活动,撸了一个PowerLink2,来支持下载。这个是采用了Dap-link,也就是CMSIS-DAP,下载丝滑。


不过,使用lks Flash就只支持Ulink和Jlink,也可以


来来回回试了多种,LKS显然是基于公版ARM内核,所以都是工作很好,所以,就不用再下载器上纠结了,哪一个都阔以的。

2. 测试GPIO的功能,新板初温就要玩点灯。厂家提供了BSP中完整滴提供了各种GPIO的输入和输出控制,这个控制完全是采用了LKS自定义的工具,没有使用CMSIS的内核,但是硬件初始化和应用的过程是完全一致的,和ST的似曾相识。
void GPIO_init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_StructInit(&GPIO_InitStruct); //³õʼ»¯½á¹¹Ìå

    //ÅäÖð´¼ü start£ºP2.11
    GPIO_StructInit(&GPIO_InitStruct);        //³õʼ»¯½á¹¹Ìå
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; //GPIOÊäÈëģʽ
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIO2, &GPIO_InitStruct);

    //ÅäÖð´¼ü stop£ºP2.12
    GPIO_StructInit(&GPIO_InitStruct);        //³õʼ»¯½á¹¹Ìå
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN; //GPIOÊäÈëģʽ
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_12;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIO2, &GPIO_InitStruct);

    //ÅäÖÃLED1£ºP0.6
    GPIO_StructInit(&GPIO_InitStruct);         //³õʼ»¯½á¹¹Ìå
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //GPIOÊä³öģʽ
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_15;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIO0, &GPIO_InitStruct);

    //ÅäÖÃLED2£ºP0.7
    GPIO_StructInit(&GPIO_InitStruct);         //³õʼ»¯½á¹¹Ìå
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //GPIOÊä³öģʽ
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_7;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIO0, &GPIO_InitStruct);

    //ÅäÖÃLED3: P0.3
    GPIO_StructInit(&GPIO_InitStruct);         //³õʼ»¯½á¹¹Ìå
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //GPIOÊä³öģʽ
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIO0, &GPIO_InitStruct);
}
这个主程序是读取按键的状态,然后LED全亮或者全灭,
int main(void)
{
        u8 key = 0;
        Hardware_init();
        GPIO_LED(ALL_OFF);
        while (1)
        {
                key = GPIO_KEY_Scan(0);
                GPIO_ResetBits(GPIO0, GPIO_Pin_15);
                switch (key)
                {
                case start_PRES:
                        GPIO_LED(ALL_ON);
                        break;
                case stop_PRES:
                        LED1_OFF;
                        break;
                        
                }
                delay(0xFFFF);
        }
}
测试一下,运行顺利,只是再GPIO的定义中LED1有一个地方是P0.15初始化的,查表应该是P0.6,修改后LED1也没亮,只是LED2,LED3亮了,应该是没有改通畅。不过,这个环节是测试芯片,应该没有问题。
3. 分析范例程序,实现电机旋转自由
3.1 围绕电机控制,属于电机学的核心课程,总体原理是比较复杂的,电机学课程在多数大学课程是可以列入四大杀手的行列的。凌欧比较贴心的给了一个科普包,刺激一下大家的小心脏,重温痛苦不堪的备考过程,还是太暖心了。这里不大展开,总体来说,多数工业或者商业都采用BLDC的三相直流电机驱动,而不是简单采用两相DC电机,就是因为成本低,控制简单。控制原理虽然复杂,但是多年积累,这些IP都已经固化了,凌欧直接给一个已经编译好的lib文件,就是告诉大家不要卷,直接来用就好了。

这样非常适合快速商业开发,节省了太多的时间,这个开发套件其实提供了一个服务包,可以快速实现电机控制,投入快速实用。
3.2 其中先测试FOC无传感器的范例代码,直接就被xxx了,显然这个是其中的NVR定义升级版本了,但是没有及时更新,选择了CMSIS Core也没有解决,这个最好还是等代码更新后再用,应该不是大问题,选择合适的引用库就可以的。耐心一点点就好。


3.3 FOC开环Hall传感器控制运行很顺利,核心的控制逻辑代码都是公开的,

这个逻辑是很多研究结果的总结,所以读代码就能看到老师一遍遍重复的原理,极对数,反电动势,死区等等,


然后连接电机,上电后顺利启动运行成功。

4. 源代码分析和使用配置
4.1 无刷直流电机(Brushless Direct Current Motor, BLDC)是取消了换向电刷,使用一个外部施加的旋转磁场,拖动通常是磁体的转子旋转,带动风扇等旋转设备,用于吸尘器,空气压缩机等旋转设备,是一种运用最广泛的电机。
    FOC(field-oriented control)为磁场导向控制,又称为矢量控制(vector control),利用旋转磁场的频率,占空比,电压等来实现转速控制,选装方向控制。这个旋转的磁场可以是各种波形,最简单的就是脉冲方波,简单调整方波的占空比,就能调整能量,但是这样调整不平顺,而且波形不好,文波过高,转换效率不高。模拟正弦波最理想,但是要求控制精准。FOC精确地控制磁场大小与方向,使得电机转矩平稳、噪声小、效率高,并且具有高速的动态响应。由于FOC的优势明显,目前已在很多应用上逐步替代传统的控制方式,在运动控制行业中备受瞩目。
    FOC按照电机有无传感器来区分,可以分为有感FOC和无感FOC。对于有感FOC,由于电机的传感器能反馈电机转子的位置信息,因此在控制中可以不使用位置估算算法,控制起来相对无感FOC简单,但是对带传感器的电机应用来说,往往对控制性能要求较高。传感器可以使用编码器,这样的精度不高,更多是采用Hall传感器,可以精确快速捕捉UWV三极磁体的相对位置,便于计算出精确的旋转磁场矢量,并可以感应出,过流,过压,超速,堵转等各种复杂的运行状态。

对于无感FOC,控制中需要通过采集电机相电流,计算反向电动势,使用位置估算算法来计算转子位置,无感FOC的控制难度较大,但是它可以避免传感器故障的风险,并且省去了传感器的成本,同时简化了电机与驱动板间的布线。
4.2 控制的过程和逻辑参见某乎,电机(三)——永磁同步电机矢量控制(FOC)
   采集和控制的电磁矢量都是三相,分别用UWV标识,作为三相电源用ABC相标识有相似之处,但是完全不同,因为UWV三相电机中任意两相接反就会使磁场旋转方向改变,所以,原则上,任意一相都可以作为A相出现。其中在输出控制是用PWM模拟出正弦波的波形,称为SVPWM,那么需要的输出控制回路是三相全控桥回路,类似下图,这也是LKS功率板核心的功率电路的原理,

   中间比较难于理解的是三相到两相的交直轴变换,就是把三相矢量变为2相正交的矢量,这是一个等效可逆的数学变换,

数学变换形如

这个过程中有大量的三角函数变换,非常消耗MCU的计算能力,所以,这部分是用了一个简化的快速计算,使用查表法计算的,实现算出对应的三角函数值,存在下属文件中,在损失一定精度的情况下,获得快速的计算。



获得了d-q平面的交轴电流和直轴电流,最主要的目的是实现PID控制,沃特,无处没有PID,像平衡两轮车,四旋翼无人机的姿态保持,就是典型的PID控制,这个又是一个大大的理论大坑,就跳过,但是,变换为为d-q平面的两维数据,就是为了大大减少PID计算的难度,否则,不会把三相克拉克变换一下成两相,再反过来变回去。

废话这么多,主要是讲,凌欧的MCU必须要保证强大的计算能力,和优化的计算方法,才能完成这个高强度的实时计算能力。
这个也是非常具有难度的事情。对于最终开发者来说,只需要在下面的function_config.h,
#ifndef __FUNCTION_CFG_PARAM_H
#define __FUNCTION_CFG_PARAM_H

#define ROTOR_SPEED_FACTOR_1US                                 (s32)(1048576)
#define ROTOR_SPEED_FACTOR                                     (s32)(ROTOR_SPEED_FACTOR_1US*(1000000/PWM_FREQ))

#define ROTOR_SPEED_FACTOR_PER_UNIT                            (s16)(MCU_MCLK/PWM_FREQ)
#define ROTOR_FACTOR_REDUCE_PER_UNIT                           (s16)(ROTOR_SPEED_FACTOR_PER_UNIT)

#define MAX_SPEED_DPP                                          (ROTOR_SPEED_FACTOR/4000)


#define HALL_LEARN_ADDR                                        0x7800

#define HALL0                                                         2
#define HALL1                                                         6
#define HALL2                                                         4
#define HALL3                                                         5
#define HALL4                                                         1
#define HALL5                                                         3

#define MOTORTYPE0                                                     1

#define HALLTYPE                                                      120
#define VERSION0                                                      0
#define VERSION1                                                      3
#define VERSION2                                                      0
#define VERSION3                                                      1
#define BEMFCOE                                                       0
#define HALL_OFFSET                                                   1600
#if (SPEED_CLOSED_LOOP == 1)
#define NUL1                                                          1
#else
#define NUL1                                                          0
#endif
#define NUL11                                                              0

#define HAND_BASE                                                 (20.0/(20+10.0))                                                                         /* ת°Ñ·Öѹ±È */

#define HBSPD_BASE                                                            (u16)(32767 / 3.6 * 1.1 * HAND_BASE)                                /* ת°ÑÆô¶¯µçѹ·§Öµ */       
#define HBSPD_MAX_EFFECTIVE                                            (u16)(32767 / 3.6 * 3.25 * HAND_BASE)                                /* ת°Ñ×î´óÓÐЧµçѹ */       

#define HBSPD_EFFECTIVE_AMPLITUDE                            (HBSPD_MAX_EFFECTIVE - HBSPD_BASE)                                        /* ת°ÑÓÐЧADC·ùÖµ */       

                /* µµÎ»×î´óËÙ¶ÈÕ¼¿Õ±È 32760Ϊµç»úµÄ¶î¶¨×ªËÙ ´óÓÚ32760ºó½øÈëÈõ´ÅÌáËÙ ×î´óµ½34660 */
#define FIRST_GEAR                                                 (32000 * 128 / HBSPD_EFFECTIVE_AMPLITUDE + 1)                 /* Ò»µµËÙ¶È ×î´ó34660 */
#define SECOND_GEAR                                         (32000 * 128 / HBSPD_EFFECTIVE_AMPLITUDE + 1)                 /* ¶þµµËÙ¶È ×î´ó34660 */
#define THIRD_GEAR                                                 (32000 * 128 / HBSPD_EFFECTIVE_AMPLITUDE + 1)                 /* ÈýµµËÙ¶È ×î´ó34660 */
#define BACK_UP_GEAR                                         (3200 * 128 / HBSPD_EFFECTIVE_AMPLITUDE + 1)                 /* µ¹³µµµËÙ¶È ×î´ó34660 */

#define HBSPD_LOW                                                            (u16)(32767 / 3.6 * 0.3 * HAND_BASE)
#define HBSPD_OVERHIGH                                                     (u16)(32767 / 3.6 * 3.95 * HAND_BASE)

#define POWER_UP_STEP_STRONG                                   12

#define TIME_1S6_BASE                                                          ((u16)160)
#define KEYIN_FILTER_TIME                                     60
#define KEYIN_FILTER_TIME1                                    -60


#define PHASE_OFFSET_MAX                                        2000
#define PHASE_OFFSET_MIN                                        -2000
#define ADC_GET_OFFSET_CNT                                      512
#define TIME_5S_BASE_20MS                                       250u

#endif /* __CONTROL_PARAM_H */
正确选择参数,并和电机参数相匹配就能够完成这一系列复杂的过程。在Kernal_code目录下,就是上述计算核心的实现方法。然后再APP Function目录下,自定义业务循环,并增加控制按钮,传感器数据采集等任务。
凌欧的开发环境,其实是一个经过验证的,完整,开源的SDK,这个是和LKS芯片同样重要,甚至是更重要的服务和产品。
4.3 代码实现上述功能
首先是入口程序,简单实现初始化,整个过程没有使用RTOS,是用中断和来实现的,对于验证后的工具,应该比RTOS的时间效率更高,

任务的实现是采用了自定义状态机结合中断组合,实现

中断任务,


在handlebarControl.c文件中实现了各种调速,控制函数,

5 小结
本次评测,收获颇丰,看似简单的电机控制评估板,技术含量十足,更可贵的是凌欧提供的代码,逻辑清晰,而且主要逻辑开放,提供了丰富的二次开发能力,非常适合快速开发。

使用特权

评论回复
评论
鸥芯电驱港港 2022-7-11 20:14 回复TA
首先感谢您的测评分享,其次感谢您对于我们的基础工程软件框架,程序下载软件(LKSFLASH)的介绍,然后对我们开源有感FOC方案进行介绍和实操;最后讲解无刷直流电机和FOC原理。总结内容精简充实,给您点个赞。 
鸥芯电驱港港 2022-7-11 20:01 回复TA
@鸥芯电驱港港 :请参考这个帖子:https://bbs.21ic.com/icview-3238060-1-1.html 
鸥芯电驱港港 2022-7-11 19:46 回复TA
3.2 其中先测试FOC无传感器的范例代码,直接就被xxx了,显然这个是其中的NVR定义升级版本了,但是没w问题:有及时更新,选择了CMSIS Core也没有解决,这个最好还是等代码更新后再用,应该不是大问题,选择合适的引用库就可以的。耐心一点点就好? 答:这个是器件库升级的原因,现在使用CMSIS内核的CORE。之前的老工程需要根据说明进行更改,后期LKS提供的工程就不会报错。 
沙发
ufbycd| | 2022-7-7 15:55 | 只看该作者
楼主所说的“两相DC电机”是步进电机吗?这个用得不少吧,起码我所处的行业,无论是自动化的设备还是智能仪器都是用的步进电机。

使用特权

评论回复
板凳
daichaodai| | 2022-7-7 20:46 | 只看该作者
就是9.9元包邮那个吗?

使用特权

评论回复
地板
北方西门吹雪|  楼主 | 2022-7-8 15:18 | 只看该作者
ufbycd 发表于 2022-7-7 15:55
楼主所说的“两相DC电机”是步进电机吗?这个用得不少吧,起码我所处的行业,无论是自动化的设备还是智能仪 ...

步进电机是另一种电机,这个驱动玩不了

使用特权

评论回复
5
ufbycd| | 2022-7-8 17:57 | 只看该作者
北方西门吹雪 发表于 2022-7-8 15:18
步进电机是另一种电机,这个驱动玩不了

步进电机做FOC所需的步骤比三相电机的要少,比如,做逆Park变换得到的两个电压直接就是步进电机两个相的电压,不需要SVPWM。
只不过步进电机的电极对数多好多,同转速下的闭环调整频率大不少,然而步进电机通常的转速都不高,也就没什么问题。

只要凌欧能出带8个预驱输出的芯片,就也能直接玩步进电机。目前情况下只能用片外预驱来跑步进电机了。

使用特权

评论回复
6
北方西门吹雪|  楼主 | 2022-7-11 09:36 | 只看该作者
ufbycd 发表于 2022-7-8 17:57
步进电机做FOC所需的步骤比三相电机的要少,比如,做逆Park变换得到的两个电压直接就是步进电机两个相的 ...

原则上都可以驱动。
但是步进电机的用途完全不同,是按照逐相控制形成单步,多步控制,控制的是行程。
这款芯片是速度和功率控制,可以控制非常大的电机,这个原理用在几百千瓦的电机经过适配也是可以的。

使用特权

评论回复
7
ufbycd| | 2022-7-11 22:34 | 只看该作者
本帖最后由 ufbycd 于 2022-7-11 22:40 编辑
北方西门吹雪 发表于 2022-7-11 09:36
原则上都可以驱动。
但是步进电机的用途完全不同,是按照逐相控制形成单步,多步控制,控制的是行程。
这 ...

我目前在做驱控一体化的步进电机驱动板,想找些尺寸小点集成度高点的芯片方案,但发现国内的电机专用芯片都只针对电动工具这种市场,凌欧、灵动、旋智这些都是这样。如果能加多两路预驱形成8路预驱就能支持自动化控制领域的市场了。因为小型自动化控制产品用的大多是步进电机,步进电机要两个H桥即8个MOS管。
实在想不明白,为何不把市场做大一点。还是说自动化控制应用是个小市场,不值得推广?

使用特权

评论回复
8
yangxiaor520| | 2022-7-12 08:08 | 只看该作者
学习了,楼主这网名牛X啊!

使用特权

评论回复
9
北方西门吹雪|  楼主 | 2022-7-12 15:33 | 只看该作者
ufbycd 发表于 2022-7-11 22:34
我目前在做驱控一体化的步进电机驱动板,想找些尺寸小点集成度高点的芯片方案,但发现国内的电机专用芯片 ...

怎么讲呢。
现有国产芯片,需要先理解和消化ST在电机控制驱动上的市场逻辑。然后,才有可能创新满足新的市场,跟跑还是比较轻松的。
你所说的这个市场不是小市场,而是一个高端市场,面向机器人的伺服控制非常高端,价格也非常高。猜测你的项目式单个伺服电机。高端机器人的伺服是有高速通讯总线的,可以实现多轴多点联动,多采用FPGA这样的方案,简单一些的也要使用CAN总线。
原则上,不会复杂的,物理原理是简单而又统一,但是需要耐心去磨,需要实践调试,以后必定是个海量市场,因为,机器人进万家也就是一眨眼的事情,都用日本伺服那谁受得了,以中国人的励精图治,无论他们怎么设置障碍,他们的这个饭碗也很快就会被端了。

使用特权

评论回复
10
上下而求索| | 2022-7-12 16:48 | 只看该作者
北方西门吹雪 发表于 2022-7-12 15:33
怎么讲呢。
现有国产芯片,需要先理解和消化ST在电机控制驱动上的市场逻辑。然后,才有可能创新满足新的 ...

楼主讲的真好,公司以前在伺服有布局,后续可以多多交流。

使用特权

评论回复
11
ufbycd| | 2022-7-12 19:47 | 只看该作者
本帖最后由 ufbycd 于 2022-7-12 19:58 编辑
北方西门吹雪 发表于 2022-7-12 15:33
怎么讲呢。
现有国产芯片,需要先理解和消化ST在电机控制驱动上的市场逻辑。然后,才有可能创新满足新的 ...

我现在做的产品并没有很高大尚,就是一个半自动化的小仪器,用到多个42跟35电机。电机多了自然就要用总线控制。
因为产品是仪器,对可靠性要求高,最好要用闭环控制方式。既要总线又要闭环,那就要做驱控一体化的驱动板了。42、35电机这么小做一体化就不能选用体积太多的芯片,所以在找高集成度的芯片方案。无奈这种芯片方案是个行业空白。

机器人在自动控制市场只是很少的一个领域,还有非常多的小型的仪器或设备。支持自动化所需的技术并不比电动工具高多少,可能就是从6个预驱变到8个而已。

使用特权

评论回复
12
北方西门吹雪|  楼主 | 2022-7-14 10:53 | 只看该作者
如果没有人提供现成的驱动,就只能自己编写驱动了,选择带CAN的芯片,就可以难度降低很多。
这方面做的最好的是西门子的英飞凌,是XMC系列,还有集成控制和驱动的IDM系列芯片,傻贵傻贵的。

使用特权

评论回复
13
机机机| | 2023-10-21 01:08 | 只看该作者
BLDC这个观测器能用吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

33

主题

109

帖子

1

粉丝