1
0
mirror of https://github.com/WangXuan95/FpOC.git synced 2025-01-28 23:52:53 +08:00

Update README

This commit is contained in:
X.Wang 2021-06-17 14:24:16 +08:00 committed by GitHub
parent b2b7d2dfcc
commit 8b900d6ff1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

120
README.md
View File

@ -9,19 +9,19 @@ FpOC
**FOC控制算法**对**传感器采样速率**和**处理器算力**提出了一定的要求,使用 **FPGA** 实现的 **FOC** 可以获得更好的**实时性**和零**延迟抖动**,并且更方便进行**多路扩展**。
本库实现了基于**角度传感器**(例如磁编码器)的**有感 FOC**(一个完整的**电流反馈环**),可以进行**扭矩控制**。借助本库,可以进一步使用 **FPGA** 、**软核 MCU** 或**外置 MCU** 实现更复杂的电机应用。
本库实现了基于**角度传感器**(例如磁编码器)的**有感 FOC**,即一个完整的**电流反馈环**,可以进行**扭矩控制**。借助本库,你可以进一步使用 **FPGA** 、**软核 MCU** 或**外置 MCU** 实现更复杂的电机应用。
| ![diagram](https://github.com/WangXuan95/FpOC/blob/main/diagram.png) |
| :---: |
| 图1系统框图 |
该项目代码有**详细的注释**,结合其它科普资料(见[6][8][9]),可以用来快速地熟悉 **FOC**
该项目代码有**详细的注释**,结合参考资料 [6~9],可以带你快速地熟悉 **FOC** 。另外,一些用户在读代码时向本人反馈了一些疑问,我将它们整理在了 [FAQ](#FAQ) 里
## 特点
## 技术特点
* **平台无关** :纯 RTL 编写,可以在 Altera 和 Xilinx 等各种 FPGA 上运行。
* 支持 **12bit 分辨率**的**角度传感器**和**相电流采样ADC**,对于>12bit的传感器需要进行低位截断。对于<12bit的传感器需要进行低位补0
* 支持 **3路PWM** + **1路EN** PWM=1 时上桥导通PWM=0 时下桥导通。 EN=0 时所有 MOS 关断。
* 支持 **3路PWM** + **1路EN** PWM=1 时上桥导通PWM=0 时下桥导通。 EN=0 时所有 MOS 关断。
* 使用 **16bit 有符号整数**进行计算,降低了资源消耗,考虑到传感器为 12bit16bit 计算是够用的。
# 运行示例
@ -34,26 +34,35 @@ FpOC
需要准备以下硬件:
* PMSM 电机
* FPGA 开发板
* 磁编码器 AS5600安装在电机上用于获取角度
* AD7928 ADC 模块,用于进行相电流采样(好像没有现成卖的,需要自己画模块)
* 电机驱动板要支持3相 EN+PWM 输入信号,并且使用低侧电阻采样法+放大器对3相电流进行放大。
* **FPGA 开发板** :需有至少 **10****GPIO** ,用来接:
* **I2C (2*GPIO)** 用来连接 AS5600 磁编码器。
* **SPI (4*GPIO)** 用来连接 AD7928 ADC。
* **PWM (3*GPIO)** 用来输出 3 相 PWM 到电机驱动板。
* **PWM_EN (1*GPIO)** 用来输出 1 路 EN (使能) 到电机驱动板EN=低电平代表所有桥臂关断)。
* **UART (1*GPIO)** ,单向(仅发送)的UART连接计算机的串口用于监测电流环的跟随曲线**可不接**。
* **PMSM****BLDC 电机**
* **获取转子角度的磁编码器**:本库支持的型号是 AS5600 ,需要安装在电机上。
* **电机驱动板**要支持3相 PWM 输入信号,并且要内置**低侧电阻采样法+放大器**对 3 相电流进行放大。
* **相电流采样的ADC**:本库支持的型号是 AD7928 ,用于采样电机驱动板放大后的 3 相电流
* 网上似乎找不到现成卖的 AD7928 模块,需要自己画 PCB。
可以直接使用我画的 电机驱动板自带AD7928立创EDA工程[在此](https://oshwhub.com/wangxuan/arduino-foc-shield),只需要把它接一个 FPGA 开发板即可。
建议使用我画的一个自带 **AD7928 ADC****电机驱动板**原理图和PCB开源[在此](https://oshwhub.com/wangxuan/arduino-foc-shield),它一个板子就能实现以上**相电流采样的ADC**和**电机驱动板**的功能。(使用的电机驱动器是 **MP6540** 芯片, 我只试过驱动小功率云台电机,没试过大功率电机)
## 硬件连接与引脚分配
见该工程的顶层文件 [top.sv](https://github.com/WangXuan95/FpOC/blob/main/RTL/top.sv) 的注释,以下外设需要连到 FPGA 的引脚上普通IO引脚即可
该工程的顶层文件 [top.sv](https://github.com/WangXuan95/FpOC/blob/main/RTL/top.sv) ,它的 IO 连接方法如下
* **晶振** 50MHz 时钟,连接在 clk_50m 信号上。
* **角度传感器 AS5600** , I2C 接口, 2根线: i2c_scl, i2c_sda
* **ADC AD7928** , SPI接口4根线: spi_ss, spi_sck, spi_mosi, spi_miso
* **3相PWM输出信号**通常接在Gate Driver上例如MP6540/DRV83014根线: pwm_en, pwm_a, pwm_b, pwm_c
* **clk_50m** 连接在 FPGA 开发板自带的 **50MHz** 晶振上。
* 若不是 **50MHz** 也没关系,读 [top.sv](https://github.com/WangXuan95/FpOC/blob/main/RTL/top.sv) 会发现,它用 PLL 把 **50MHz** 转换成 **36.864MHz** 去用,所以你只需要修改 PLL 的配置,把输入频率改成板上晶振的实际频率,输出频率仍保持 **36.864MHz** 即可。
* **i2c_scl, i2c_sda** 连接 AS5600 (磁编码器) 的 I2C 接口。
* **spi_ss, spi_sck, spi_mosi, spi_miso** 连接 AD7928 (ADC芯片) 的 SPI 接口。
* **pwm_a, pwm_b, pwm_c** 连接电机驱动板的 3 相 PWM 信号。
* **pwm_en** : 连接电机驱动板的 EN (使能) 信号。
* 如果电机驱动板没有 EN 输入,则不接。
* 如果电机驱动板有 3 路 EN 输入,每个对应 1 相,则应该进行 1 对 3 连接。
* **uart_tx** 连接 UART 转 USB 模块,插入计算机的 USB 口,用于监测电流环的跟随曲线,**可不接**。
另外还有一个 UART 发送信号 (uart_tx) 是可选的,可以把它连接在 UART 转 USB 模块上,通过 UART 来监测电流环的跟随曲线。
连接好后别忘了使用 Quartus (或者手动修改[./FPGA/foc.qsf](https://github.com/WangXuan95/FpOC/blob/main/FPGA/foc.qsf))根据实际情况**修改FPGA芯片型号****修改引脚约束**。
连接好后别忘了根据实际情况使用 Quartus (或者手动修改[./FPGA/foc.qsf](https://github.com/WangXuan95/FpOC/blob/main/FPGA/foc.qsf)**修改FPGA芯片型号****修改引脚约束**。
## 调参
@ -123,20 +132,83 @@ FpOC
在**图1**中:
* **淡橙色**部分是FPGA外部的硬件包括Gate Driver、3相半桥(6个MOSFET)、采样电阻、放大器、ADC芯片、角度传感器等部件取决于电路使用什么方案。例如有些集成度很高的芯片例如MP6540可以把Gate Driver、3相半桥、采样电阻、放大器集成在同一个芯片里。
* **淡橙色**部分是FPGA外部的硬件包括
* Gate Driver、3相半桥(6个MOSFET)、3相采样电阻+放大器 。(这些通常集成在**电机驱动板**里)。
* 3相采样 ADC。
* 角度传感器。
* **粉色**部分是FPGA中的**硬件相关逻辑**,即传感器控制器,如果角度传感器和 ADC 型号变了,这部分代码需要重写。
* **青色**部分是FPGA中的 FOC 的固定算法,属于**硬件无关逻辑**,一般不需要改变。
* **黄色**部分是**用户自定逻辑**,用户可以修改 user behavior 来实现各种电机应用。或者修改 uart_monitor 来监测其它变量。
另外,除了 [pll.v](https://github.com/WangXuan95/FpOC/blob/main/RTL/pll.v) 外,该库的所有代码都使用纯 RTL 编写可以轻易地移植到其它厂商Xilinx、Lattice等的 FPGA 上。 [pll.v](https://github.com/WangXuan95/FpOC/blob/main/RTL/pll.v) 只是用来把 50MHz 时钟变成 36.864MHz 时钟的,只适用于 Altera Cyclone IV FPGA当使用其它厂商或系列的FPGA时需要使用它们各自的 IP 核或原语例如Xilinx的clock wizard来代替。
[top.sv](https://github.com/WangXuan95/FpOC/blob/main/RTL/top.sv) 和 [foc_top.sv](https://github.com/WangXuan95/FpOC/blob/main/RTL/foc/foc_top.sv) 注有详细的注释。如果你了解 FOC 算法,可以直接读懂。如果刚入门 FOC可以结合参考资料[6][8][9]去阅读。
[top.sv](https://github.com/WangXuan95/FpOC/blob/main/RTL/top.sv) 和 [foc_top.sv](https://github.com/WangXuan95/FpOC/blob/main/RTL/foc/foc_top.sv) 注有详细的注释。如果你了解 FOC 算法,可以直接读懂。如果刚入门 FOC可以结合参考资料[6~9]去阅读。
## 可扩展功能
* 使用自己编写的模块来代替 [as5600_read.sv](https://github.com/WangXuan95/FpOC/blob/main/RTL/sensors/as5600_read.sv),以适配其它型号的角度传感器。
* 使用自己编写的模块来代替 [adc_ad7928.sv](https://github.com/WangXuan95/FpOC/blob/main/RTL/sensors/adc_ad7928.sv),以适配其它型号的 ADC。
* 在 [top.sv](https://github.com/WangXuan95/FpOC/blob/main/RTL/top.sv) 中添加外环(速度环、位置环等)进一步实现各种电机应用。
# FAQ
一些用户在读代码时向本人反馈了一些疑问,我将它们整理如下。
### 关于 PCB 设计
* **问** **相电流低压侧3电阻采样需要运放放大电流信号才能作为AD输入但你[开源的PCB]((https://oshwhub.com/wangxuan/arduino-foc-shield))似乎找不到运放放大?**
* **答** 我[开源的PCB](https://oshwhub.com/wangxuan/arduino-foc-shield)使用了一体化的三相无刷电机驱动芯片MP6540U13相电流采样电阻和放大器是集成在里面的。请注意MP6540的 SOA, SOB, SOC 三个引脚,它们就是三相电流放大后的电压输出。
### 关于 FOC 中的数学计算
* **问** **三电阻采样后的电流重构的那部分代码如何理解?为什么 ia = ADCb + ADCc - 2*ADCa **
* **答** 我们知道电机的相电流 ia, ib, ic 是双极性的即有正有负的分别代表流出电机和流入电机但我们常用的ADC往往都是单极性的即只能采样正电压。那么相电流采样-放大电路就必须考虑双极性到单极性的转换问题工程上用的方法往往都是反向放大加偏置包括MP6540内置采样-放大电路也是这种方案它输出给ADC的电压遵循公式
ADCa = -R × ia + Voff
ADCb = -R × ib + Voff
ADCc = -R × ic + Voff
其中 R 是放大系数R>0也叫跨阻放大系数因为 R 的量纲和电阻一样因为反向放大所以加了负号。Voff 是偏置电压,以此保证 ADCa, ADCb, ADCc 是单极性的。另外又有基尔霍夫电流定律KCL
ia + ib + ic = 0
联立以上公式,推出:
3 * Voff = ADCa + ADCb + ADCc
令 R = 1/(3*k) ,于是:
ia = (Voff - ADCa) / R
= k × (3 * Voff - 3 × ADCa)
= k × (ADCa + ADCb + ADCc - 3 × ADCa)
= k × (ADCb + ADCc - 2×ADCa)
于是就有了你问的 ia = ADCb + ADCc - 2×ADCa 。 你肯定会疑惑,系数 k 哪儿去了这个并不在乎因为整个FOC都是线性系统通过调整PID参数能跑就行系数只在理论分析时有用。
* **问** : **你的程序里是不是都没有在乎系数K包括clark变换中得到的Iα和Iβ和ia、ib、ic也并没有满足严格的公式关系程序中得到的Iα和Iβ是理论值的2倍。这是不是也可以用调整PID参数的思想来解释**
* **答** 是的,我很多地方的代码也与理论公式的系数不同,比如 clark 变换公式本来是:
Iα = Ia - Ib/2 - Ic/2
Iβ = √3/2 * (Ib - Ic)
我多乘了个2
Iα = 2 * Ia - Ib - Ic
Iβ = √3 * (Ib - Ic)
这是出于避免整数计算的截断导致的数据位丢失,比如 Ib/2 就会让 Ib 的最低 bit 丢失。不过实际上这种小误差基本不会影响控制质量。这种系数问题可以通过 PID 调参来消除。
* **问**: **你的代码中的 cartesian2polar.sv 是把电压矢量从转子直角坐标系 (Vd, Vq) 变换到转子极坐标系 (Vrρ, Vrθ),目的是什么?**
* **答** 书上一般会说 SVPWM 模块输入的是定子直角坐标系下的电压,但我实现的 SVPWM 输入的是定子极坐标系下的电压,两种方法在数学上是等价的。而且 SVPWM 在 FPGA 里用查找表(ROM)实现,因此两种方法对电路复杂度影响不大。另外,输入极坐标系的 SVPWM 还带来 2 个好处和 1 个代价,好处 1 是更方便在开发过程中让电机开环地转起来(只需要让角度递增即可)。好处 2 是极坐标系下的 park 变换更简单,只需要用电压在转子坐标系中的角度减去电角度就能得到电压在定子坐标系中的角度。 代价是需要在 PID 的后面、park 变换的前面实现一个直角坐标系转极坐标系的运算,即 cartesian2polar.sv
### 关于 ADC 采样时机
* **问** **AD7928只有一个T/H(采样保持器)也就意味着这个AD一次只能保持一个通道的数据也就是说当通道1 打开的时候采集A相的电流然后采集完再打开通道2采集B相的电流那么这并不是一个同步采集的过程如何实现AD采样三相电流的同步输出**
* **答** 在电流采样问题上,我们与大多数 FOC 方案相同,因为 MP6540 里的采样电阻在下桥臂,所以规定 SVPWM 在每个控制周期(约 55us对应频率18kHz内至少有一段时间里 3 相都是下通上闭称为采样窗口。FOC的基础振幅也就是 foc_top.sv 里的 MAX_AMP 参数)越大,采样窗口越短。当 MAX_AMP=9'd511 (最大值) 时,采样窗口长度就是 0 了。而默认的 MAX_AMP=9'd384 大概会让采样窗口长度为十几us。
AD7928 只有一个T/H所以采样窗口内要做 3 次采样,这个过程是 hold_detect.sv 和 adc_ad7928.sv 共同控制的hold_detect.sv负责在采样窗口开始时延迟一段时间来让电流趋于稳定后发出 sn_adc 信号脉冲,来告诉 adc_ad7928.sv 可以开始工作了(可以通过 foc_top.sv 里的 SAMPLE_DELAY 来调整该延迟)。然后 adc_ad7928.sv 内部就会自动串行地完成 3 个通道的采样最后再同步提交3个采样结果提交的同时产生 o_en_adc 信号脉冲。注意adc_ad7928.sv是一个通用的 AD7928 控制器,每收到一个 i_sn_adc 信号脉冲,就进行一系列串行采样。其中采样多少次,每次采样哪一个通道,都可以通过 adc_ad7928.sv 里的 parameter 来配置。所有通道采样结束后产生o_en_adc信号脉冲同时同步提交所有通道的结果。
我把 foc_top.sv 用来连接 ADC控制器的接口也就是sn_adc, en_adc, adc_a, adc_b, adc_c 这几个信号设计成同步读入3通道数据是出于通用性、简约性和可移植性的原则考虑因为这样的同步读入接口是 ADC 的一种高度抽象最容易让人理解其时序sn_adc脉冲命令ADC控制器开始工作。en_adc指示ADC读取器结束工作同时 adc_a, adc_b, adc_c 上产生结果)。如果用户用了其它 ADC 型号,只需按照这个时序的抽象来具象地编写 ADC 控制器即可,而 foc_top.sv 并不关心拟用的是1个串行的ADC还是3个并行的ADC反正你都要给我同步提交。当然用户必须自己算好 hold_detect.sv 的延时 + ADC 采样三个通道(也即 sn_adc 脉冲和 en_adc 脉冲的时间差) 是小于采样窗口的长度的。
* **问** **进行串行采样的时候不会出现这样的问题第一个时钟周期采到的是A相的电流第2个时钟周期采的是B相第3个时钟周期采到的是C相而我们知道相电流是正弦变化的这三个时钟周期采的A B C 三相电流并不是同一时刻的相电流,因此这将产生误差,而时钟周期是很短的,是不是产生的误差几乎可以忽略不计呢?**
* **答** 首先指正一个不准确的地方, AD7928 的接口是 SPI (一种串行接口),其采样是多个时钟周期(而不是一个时钟周期)内完成的。因此三相的采样间隔是几十个时钟周期(具体数字我忘了,你可以仿真确定一下)。
虽然不同步但3相的采样毕竟都是在同一个控制周期的采样窗口几微秒内。而相电流的变化通常以控制周期即几十微秒为尺度变化例如 3000r/min50r/s的转子若极对数=7其相电流是350Hz周期28ms的正弦波其变化在几微秒内是可以忽略的。
### 关于时钟周期和控制周期
* **问** **时钟频率为什么选择36.864MHz有什么特殊含义嘛我如果直接用FPGA的50MHz不经过PLL变成36.864MHz)会出现什么问题呢?**
* **答** 其实选 36.864MHz 只是因为可以让控制周期为 36864/2048 = 18kHz凑个整。
foc_top.sv 和 as5600_read.sv 对时钟频率是没有要求的,多高都可以(唯一的限制是频率太高时序不收敛)
但 adc_ad7928.sv 限制了频率不能大于 40.96MHz,因为 ADC7928 的 SPI 时钟不能超过 20.48MHz,而 adc_ad7928.sv 内部用驱动时钟2分频作为SPI时钟。
综上,时钟频率是可调的,但要小于 40.96MHz。
* **问** **代码里 控制频率= 时钟频率 / 2048为什么 我觉得控制频率和时钟频率应该是没有必然的联系时钟频率是FPGA的时钟频率而控制频率是pwm的频率一般是几十khz你是根据控制频率来确定的时钟频率嘛**
* **答** 理想地来讲FPGA时钟频率和控制周期确实没有关系但要考虑实际PWM不也是FPGA的时钟驱动的既然如此必然有个分频系数控制频率 = 时钟频率 / 分频系数别的驱动器可能具有可调的分频系数但FpOC里为了简单分频系数=2048。这意味着 FpOC 如果要调节控制频率就只能调时钟频率目前受限于上述ADC7928的频率限制最高的控制频率是 40.96MHz/2048=20kHz。
# 参考资料