2024-09-24---foc学习记录

1.搭建开发环境和上手例程

组装BLDC驱动方案

ESP32-PlatformIO上完成了基础的simpleFOC闭环速度环测试,V3P板子性能还是比较好的,而且simpleFOC的兼容性比自带的DengFOC要好得多。
首先是电机安装,以后散装买的BLDC同样需要这样的步骤:

  • 在电机底座贴上磁铁,并使用打印件与磁编码器固定;
  • 编码器连线至主控制器;
  • 电机固定好后连接驱动板;
  • 连接电源。
搭建开发环境

这里与例程环境不同,使用VScode+PlatformIO平台进行ESP32的开发,搭建好后步骤是创建新工程选择板子lolin32_lite和依赖库simpleFOC,导入.ino文件重命名为.cpp文件,在文件中根据编译报错引用较新的C++库及其函数即可。
在这里插入图片描述

根据FOC知识和代码提示,修改电机参数的极对数和供电电压,硬件不同需要在意编码器相关配置和引脚配置,初步调试无需在意PID参数。
串口(这里是COM20)连接电脑配置好,打开电源即可烧录测试。这里提供的电源是DC电源,询问客服调试可以使用DC电源的DC头出线提供插电,比电池供电10min耐用多了。

烧录代码成功正常,打开串口输入目标速度即可实现速度环控制。至于DengFOC遇到库文件需要修改且无法正常使能的问题,只能说以后再考虑了,目前更想熟悉的是simpleFOC本身。


2.初步学习系统辨识与尝试

看了看@龙胆也老师系统辨识的系列文章,很值得尝试学习,充分发挥我们电机的学习价值。

然后是到421施公队中学习MPC和LQR算法的入门和实践,之后系统辨识模型成功后就可以上手尝试了。MPC的核心流程就是上电后捕获阶跃响应数据进行观察,然后是计算收敛+能耗的代价函数得到最优控制下的状态变量, …to be continued,LQR的核心流程是…to be continued

观看相关文章和视频后,首先是在simulink中尝试搭建简单的控制回路,发现没有装相关APP导致无法将控制节点线性化以导出传递函数,没事matlab中的model identification就够用。

短期来讲,适配自己的ESP32开发板是可行的,但是自己的电机需要适配磁环电源线磁编码器,需要一定时间和试错成本。

  • 疑问:

    • 零极点添加减少意味着什么
    • simulink输出传递函数的另辟蹊径
    • simpleFOC studio可以提供的电机检测参数
  • 解决了:
    以ROM取代RAM代价获取采样数据(过程存数组+事后发数据)
    数据画图
    数据包采样时间确定
    SimpleFOC Studio的使用方式
    拟合模型准确度不高+PIDF参数调整发散
    得到板子PCB,可以更换主控和移植算法
    电机磁环、信号线拆除、磁编码器和螺丝准备

  • TODO:

    • 移植FOC,替换主控
    • 优化数据序列
    • 数据滤波处理

参考资料:

  1. Simulink-采样时间详解_simulink采样时间设置-CSDN博客
  2. 自控原理之系统辨识–入门介绍 - 知乎 (zhihu.com)
  3. matlab系统辨识+调PID,全网最完整步骤(v-rep仿真) - 知乎 (zhihu.com)
  4. 开源 | RoboMaster步兵云台参数辨识 - 知乎 (zhihu.com)
  5. 拒绝瞎调,用matlab,自动调节PID参数 - 知乎 (zhihu.com)
  6. 【教程】【SimpleFOC Studio 图形化调试软件的使用】DIY不足百元的无刷电机闭环驱动–SimpleFOC(5)哔哩哔哩_bilibili

3.移植到esp32s3更新simplefoc库

完成了对simpleFOC主控的部分移植,还是Arduino框架,移植到esp32s3上。经测试部分功能未成功,需要进一步解释测试。此行目的在于了解所需硬件资源,方便后续不同平台移植。

  • 待解决问题
    • MPU6050读取失败
    • 不用电流检测,力矩控制无法进行

首先是硬件连接,确定好所需硬件资源,PWM6个,2个I2C,2个使能EN端,VCC-GND。最好一开始按顺序分配好,符合物理直觉。好吧I2C不符合,所以被坑了一次,如

/**
 * revised by xiyg33:
 * pinset with esp32s3
 * M0: PWM:15,14,13 EN:4
 * M1: PWM:18,17,16 EN:5
 * I2C0: 11,12
 * I2C1: 8,9
*/

然后是platformIO的平台移植,根据esp32s3的板子创建项目并导入simpleFOC库,建议不要指定上传速度,默认速度会更快。
在这里插入图片描述

然后是测试例程文件,首先应该测试通信和数据获取,在本例中是测试I2C通信和磁编码器AS5600和MPU6050的数据获取。
在这里插入图片描述

结果不出人意料的失败了,串口出现

[!error] “MOT: Failed to notice movement”
解决: 经查询是无法感受到角度变化, 正确连接上I2C的话, 可以尝试更换I2Cone和I2Ctwo的程序指定引脚. 更换即可成功。

然后是测试电机闭环运动,不出意料又错了。

[!error] simpleFOC库引用esp32的部分宏代码而不是esp32s3的,无法成功编译。
此时反复导入esp32s3的相关依赖库都没作用。
解决:更新simpleFOC库为2.3.1,果然有esp32s系列。

在这里插入图片描述

编译成功就可以按照硬件配置使用电机咯。


4.学习移植minifoc项目

测试了下vscode对stm32的支持,找到Embedded IDESTM32 Project Assistant两个插件,前者支持keil和IAR等工程导入,后者支持CubeMX工程导入,不过没有查看教程都没有完成导入工程,出现xxx未定义的情况,显然需要查看相关教程以补充实践。经过搜索发现PlatformIO好像也支持CubeMX工程和标准库工程导入,之后也可以试下。

by the way: 要说编译调试,估计还是比不上keil的。不过编写代码倒是值得一试。

在这里插入图片描述

做的比较多的工作就是移植MiniFOC代码到stm32上,初步分配下资源。
然后是移植MiniFOC的算法部分,遇到很乌龙的几个问题:

  1. 某些文件使用未定义符号不会报错;
  2. stm头文件之间会互相重复定义;
  3. main.h无法重复引用,除了main.c其他文件无法使用;
  • 问题一,keil似乎有一个机制,就是在同一文件多次使用的函数只会发出warning说declaration implicity,导致只能认真查询;还有一个机制就是,前面头文件错误了后面就不会继续检查下去了,这给移植带来了不少的问题,导致我之后又依赖了他的系统函数部分,等成功测试了还是得自己写。
  • 问题二,其实是使用HAL库却又引用标准库头文件导致的重复定义;
  • 问题三,其实MiniFOC的main.h在HAL库自动生成的main.h面前失效了,将声明部分移植到HAL下的main.h就好了。

对于MiniFOC,其实比较欣赏项目:

  • 用到CORTEX芯片的代码使能某些功能
  • PID-HANDLER的形式装载不同的闭环信息,只需一个PID函数计算
  • 裸机代码,但是有较为完善的flash配置+通讯协议实现+系统参数表+错误提示
  • 底层级的数学优化

5.处理常见移植问题

[!warning]

  • 通信问题,适配vofa观察数据波形
  • 在移植过程中被迫重新分配资源
  • 碰到任务处理频率问题⚠

  • 记录下
    进入KEIL调试,多次设置断点,发现主循环前的MX语句能一句句执行完,一进入user语句马上跳入systick的不断的计时中断中。

避免其他程序和TIM影响因素,转到简单程序进行迅捷测试,只测试UART中断、空中断TIM和SYSTICK。

在1msSYSTICK中断情况下,UART可以正常应答并提供HAL_GETTICK时间戳。
反复修改SYSTICKCONFIG没效果,~~才发现是没有使能mysystick_config.~~然而使用1μs中断,无法应答与发送时间戳。

反复观看以前的SYSTICK使用,1μs的延时不使能中断,VAL溢出就离开函数,显然72MHz无法支持1μs中断。至此,加深了对SYSTICK的中断使用认识,config的修改以及函数库的填补。


7.算法部分的关键函数过程记录

simpleFOC设置电压限制:setPWM()

void _setPwm(FOC_T *hfoc, float Ua, float Ub, float Uc) {
  Ua = _constrain(Ua, 0.0f, hfoc->voltage_limit);
  Ub = _constrain(Ub, 0.0f, hfoc->voltage_limit);
  Uc = _constrain(Uc, 0.0f, hfoc->voltage_limit);
  
  float dc_a = _constrain(Ua / hfoc->voltage_power_supply, 0.0f, 1.0f);
  float dc_b = _constrain(Ub / hfoc->voltage_power_supply, 0.0f, 1.0f);
  float dc_c = _constrain(Uc / hfoc->voltage_power_supply, 0.0f, 1.0f);

  __HAL_TIM_SET_COMPARE(hfoc->tim, TIM_CHANNEL_1, dc_a * hfoc->pwm_period);
  __HAL_TIM_SET_COMPARE(hfoc->tim, TIM_CHANNEL_2, dc_b * hfoc->pwm_period);
  __HAL_TIM_SET_COMPARE(hfoc->tim, TIM_CHANNEL_3, dc_c * hfoc->pwm_period);
}

函数传入函数指针的例子:FOC_Bind_SensorGetOnceAngle

typedef float (*FUNC_SENSOR_GET_ONCE_ANGLE)();
typedef struct {
  TIM_HandleTypeDef *tim;  // PWM定时器
  ......
  FUNC_SENSOR_GET_ONCE_ANGLE Sensor_GetOnceAngle;
} FOC_T;
/**
 * @description: 绑定用于获取单圈弧度值的函数(0 - 6.28)
 * @param {FOC_T} *hfoc foc句柄
 * @param {FUNC_SENSOR_GET_ONCE_ANGLE} s 函数指针
 * @return {*}
 */
void FOC_Bind_SensorGetOnceAngle(FOC_T *hfoc, FUNC_SENSOR_GET_ONCE_ANGLE s) {
  hfoc->Sensor_GetOnceAngle = s;
}

HAL对象 AS5600_T

AS5600_T G_SENSOR_A;

float Sensor_GetOnceAngleA() { return AS5600_GetOnceAngle(&G_SENSOR_A); }
float Sensor_GetAngleA() { return AS5600_GetAngle(&G_SENSOR_A); }
void Sensor_UpdateA() { AS5600_Update(&G_SENSOR_A); }
float Sensor_GetVelocityA() { return AS5600_GetVelocity(&G_SENSOR_A); }

void FOC_HAL_InitA(FOC_T *hfoc, I2C_HandleTypeDef *h2ic) {
  AS5600_Init(&G_SENSOR_A, h2ic);
  FOC_Bind_SensorUpdate(hfoc, Sensor_UpdateA);
  FOC_Bind_SensorGetOnceAngle(hfoc, Sensor_GetOnceAngleA);
  FOC_Bind_SensorGetAngle(hfoc, Sensor_GetAngleA);
  FOC_Bind_SensorGetVelocity(hfoc, Sensor_GetVelocityA);
}

AS5600测速法:

a->prev_angle_ts = HAL_GetTick();
// 计算速度
float AS5600_GetVelocity(AS5600_T *a) {
  float ts = (a->prev_angle_ts - a->vel_prev_angle_ts) * 1e-3;
  if (ts <= 0) ts = 1e-3f;
  float vel =
      ((a->rotation_offset - a->vel_rotation_offset) +
       (a->prev_angle - a->vel_prev_angle) / (float)AS5600_RESOLUTION * _2PI) /
      ts;
  a->vel_prev_angle = a->prev_angle;
  a->vel_rotation_offset = a->rotation_offset;
  a->vel_prev_angle_ts = a->prev_angle_ts;
  return vel;
}

define的参数放在.c,typedef放在.h里面

  • miniFOC的电气角度算法
float electric_angle = (float) (tmp_mechanical_angle % (ENCODER_RESO / POLAR_PAIRS)) * ELECANGLE_COEFFICIENT;

电气角度:机械角度 * 极对数 - 零位电气角度
该行代码为机械角度 % 该扇区的角度编码值 * 电气参数(极对数 / 编码值)

  • simpleFOC的电气角度算法
float FOCMotor::electricalAngle(){
  // if no sensor linked return previous value ( for open loop )
  if(!sensor) return electrical_angle;
  return  _normalizeAngle( (float)(sensor_direction * pole_pairs) * sensor->getMechanicalAngle()  - zero_electric_angle );
}

normalize限制在[0,2pi]内,电气角度=方向 * 极对数 * 机械角度 - 零位电气角度

奇怪的电气角度(LL库例子)获取方法:

//获取编码器的机械角度,真实的物理角度
//获取电角度角度,FOC电角度
void Get_PWM_Encoder_Angles(void)
{
  pwm_encoder.angle = pwm_encoder.duty * 360.0f;
  pwm_encoder.angle_rad = pwm_encoder.duty*2*PI;
	pwm_encoder.angle_rad_offset = 6.045f; //手动找到的零点,后续通过函数调用获得
	if(pwm_encoder.angle_rad>=pwm_encoder.angle_rad_offset) //减去零点偏置,相当于取余
	{
		 pwm_encoder.angle_rad = pwm_encoder.angle_rad - pwm_encoder.angle_rad_offset;
	}
	else
	{
		 pwm_encoder.angle_rad = 2*PI - pwm_encoder.angle_rad_offset + pwm_encoder.angle_rad;
	}	
	pwm_encoder.electronic_angle = pwm_encoder.angle_rad*MOTOR_POLE;
}
  • Odrive移植用户锐评
    在simpleFOC中,没有估算下次转过的角度,只是简单的加了_PI_2,我觉得这也是限制了SimpleFOC最大转速的一个原因,因为转速足够快的话,一个电周期完全有可能转过_PI_2个电角度。
    在这里插入图片描述

来自Odrive-foc.c
在这里插入图片描述

miniFOC存在的问题,电气角度的值域理论上比其他实现的都要小,它相当于只处理某一扇区的编码值,似乎是假设该工作周期(8kHz)内编码不会超过该扇区,否则忽略掉该变化,这似乎是个危险的操作,根据上面代码的学习可以知道,simpleFOC是将突变处理为2PI,而Odrive则会在变换计算过程中再次测量保证可以获取突变。至于到底能不能输出波形,发现需要配置PID.expect为非0。

参考资料:

  1. miniFOC/Software/foc/Hardware/Src/foc.c at main · HangX-Ma/miniFOC (github.com)
  2. 首页 | Arduino-FOC (simplefoc.com)

8.移植过程换模块的反复调试

  • 移植难崩的mpu6050

问题最终体现在上位机不能正确获取两个从机数据,卡死在某固定几次发送,所以一开始就调UART配置,以为是速率过高导致0数据重合,降低波特率也有同样的问题,而提高波特率还可以在这个固定失败时间内多发几次。问题不太指向UART,只是照常发0数据而已,通过ST-LINK仿真发现也没有长时间停在UART,倒是检查出IIC缓冲区没有数据,IIC混用了UART的DMA,不过改完IIC接收发送函数也无济于事。

无心之余出去逛逛,跟朋友聊聊天骂骂自己垃圾,认真核对从机地址,反复切换从机地址的移位并且|0x01,没想到般测试成功了Encoder的数据,换回自己的实现也可以,这说明不是IIC的问题。再写个测试ID的函数测试出了系统就4个iic响应地址,两个iic设备的读写地址,104和208,分别对于encoder的0x36和MPU的0x68,而且使用MPU的MPU_GETID()有应答,这说明至少板子的MPU没问题,那个散装的MPU 电容焊锡都飞起来了,估计是坏了,还好测出来,这就拿去送葬TMD😅

把任务放回两个定时器线程,马上打回原形,改变线程时间也没用,不过经过以上摸爬滚打,几乎可以确认一件事—跟线程有关,多半也就跟系统分配的资源有关。
之前反复看iic调用经常是HAL_OK就没细看,闲着也是闲着,认真看完一次IIC_MASTER_TRANSMIT()执行,看了几遍,几乎是幸运般才确认进入了一次HAL_ERROR错误,判断条件是if(IIC_xBufsize == 0)。前面的一些操作是HAL_Locked(), 失败后就解锁HAL_unLocked(),结合我对Linux-Thread使用的了解,已经估计出错误是系统调用互斥资源失败导致了,表现为IIC的两个从机使用同一个iic_RxBufiic_TxBuf跟懂RTOS的同学多沟通了几下,帮助我更深入的思考到

也许HAL操作实现了某些系统保护, 在关闭系统中断时__disable_irq__()给函数调用的资源实现上锁HAL_Locked(),重新开始中断然后此时更高抢断优先级的线程的中断嵌套 访问资源失败返回0数据

第二天修改每个从机分配独立资源和修改好传送的数据编号,总算同时成功读取两个从机所需数据,他真的我哭死🥲,这就滚去学RTOS。

  • 结论:

MPU6050的从机地址|0x00或者|0x01都没问题,均可以应答
这个工程iic时钟初始化要比GPIO滞后也无所谓
数组初始化可以用memset


9.对SVPWM合成向量的理解记录

参考自:PWM那些事儿 - 知乎 (zhihu.com)

SVPWM的数字实现

很多文献和教科书都会去讲怎么计算8个电压矢量的作用时间,怎么按顺序去作用电压矢量,该过程实在是太虐心,太考验人的耐性。而最开始搞SPWM的人不死心,想看看SVPWM这种电压矢量作用方式下,等效的载波是什么样的。于是很多大神上场发挥作用,最后研究下来,发现其调制波是在正弦波的基础上,注入了三次谐波。

而且三次谐波很特别,并不是一个三次正弦信号,而是类似三角波的波形。很幸运,这个注入的谐波还有解析式,Uz=middle(Ua,Ub,Uc),也即是三相输出电压ua,ub,uc的 中间值。那就好办了,SVPWM的数字实现时,不用再采用复杂的空间位置计算了,只需要求取中间值,进行叠加即可。
更进一步研究,对Uz采用不同的取值,除了可以得到SVPWM外,还可以变化得到5段式pwm、过调制的PWM等等。

应该是中间值的一半吧,也就是最常见的表达式-(max + min)/2
评论 by SAMPAN

SVPWM模拟

参考:【精选】foc学习笔记2——svpwm_foc svpwm_jdhfusk的博客-CSDN博客
有了这8个基本矢量,我们终于能用它们来合成任意矢量了。假设一个任意矢量落在第一扇区,也就是U4和U6之间(不要问为什么要落在这里而不是其他地方,因为它是每隔60°都是一样的,算明白一个就行)。那么我们就可以使用U4、U6以及两个零矢量去合成它。

​ Uref就是我们想要合成的目标矢量,Ts为mos管一次开关的时间。然后由伏秒平衡原理可以得到Uref乘以它的作用时间就等于U4乘以它的作用时间再加上U6乘以它的作用时间:

U r e f ∗ T s = U 6 ∗ T 6 + U 4 ∗ T 4

然后我们就可以列出方程求出T4和T6:(其实就是高中的三角函数并不难,这里就不推导了)

​ T4和T6便是我们最终想要的结果,得到它基本就得到了pwm三个通道的占空比大小。后边还有七段式和五段式的svpwm,其实区别就在怎么分配T4、T6以及零矢量的作用时间,这边已经讲得有点多了,大家自己下去看吧。最后注意几点,零矢量的作用时间等于Ts减去T4和T6,对于七段式的svpwm,T0和T7均匀分配。如果Ts刚好等于T4加T6,那么意思就是出了全力;如果T4加T6比Ts还要大,那就说明你想要的Uref已经超出了系统能够输出的范围,这是绝对不允许的。如何判断想要的矢量有没有超出系统的输出范围,只要看 m是不是小于等于1就行,换句话说就是Uref要小于等于三分之根号三倍的Udc

PWM计数模式在电机驱动方式的影响:

参考:
为什么电机控制PWM都要配置成中心对齐模式? - 知乎 (zhihu.com)
嵌入式学习之PWM (baidu.com)

by 深漂赵工

向上向下计数和向上计数模式在工控行业很常见,比如Boost/Buck电路常用向上/向下计数模式,DC-AC逆变电路常用向上-向下模式,方便中心对齐,上下管子互补比较好处理。

by 孙晓

使用过程里面最重要的一点就是方便。要是说递增,递减,和递增递减有什么区别,就是使用方便程度不一样。
SVPWM调制计算完成之后就是个时刻,用递增递减计数模式送入比较寄存器,可以自动生成对称的七段式或者五段式的pwm。大家可以想想用递增计数或者递减计数处理这个得加多少中间寄存器。

by 嘉科

PWM配置成中心对称模式,将使开关时间点尽可能散开,增强电流的稳定性;假如你设置成边缘对齐模式,那么在计数器为0或者TPR时,你会发现三个桥臂一起切换开关,此时电流会不稳定。

by 石头

中心对齐的是为了确保三相pwm开关的中心时刻是对齐的,方便在中间时刻插入零矢量以实现电压合矢量的灵魂(?)调整。也方便在pwm开关的中心时刻避开开关噪声做电流等模拟量的采样

Electric motor Control-DC.AC,and BLDC Motors By Sang Hoon Kim

一页期刊说明,更小的电流纹波与更高的纹波(ripple)频率;更高的电压调制范围;能把零矢量安排在转换序列的两端,得到最小切换(switch)频率(?);向量转换只需一次切换, 从高到低->从低到高.

by 稚晖君

现在一个周期内所有状态的持续时间我们都得到了,还差一个顺序,也就是各个状态切换的顺序
问题:难道不是任意顺序都可以嘛?反正是做积分,重要的是持续时间而不是顺序,一个周期内怎么切换都行啊。
是的,理论上任何切换顺序都是ok的,但是实际中我们需要考虑更多限制,比如因为MOS管存在开关损耗,我们希望能尽量减少MOS管的开关次数,那么以最大限度减少开关损耗为目的,我们就可以设计出下面的切换顺序:

上图中可以看出来,在每个状态切换的时候,都只有一个相发生了转变:000->100->110->111->110->100->000, 这也是所谓的七段式SVPWM调制法。
同时我们通过在合理的位置插入两个零矢量,并且对零矢量在时间上进行了平均分配,以使产生的PWM对称,从而有效地降低了PWM的谐波分量。

PWM移至供电电压中心

by DengFOC

代码中,我们给ua​,ub​,uc​每项加入了一个:voltage_power_supply/2项,这个是什么呢?这个其实是供电电压/2,比如,如果给板子的供电电压是12V,那么这个voltage_power_supply/2=12/2=6,它的存在主要是将生成的ua​,ub​,uc​曲线平移到供电电压的中间,因为原始的ua​,ub​,uc​一个类似正弦曲线的输出形式,会有电压 < 0的部分,避免产生电压< 0部分(实际的电路中我们是没办法生成负电压的),因此我们需要把所有的电压都维持在正的情况,这也是为什么我们要将电压平移。

直驱与带减速器的区别:

直驱响应速度与精度更高,维护成本更低,虽然制造成本高,高转速扭矩相对较小,因此可以广泛应用于机器人、医疗电子等领域;带减速器,使用更多的传动装置,维护成本高,但是可产生力矩大,电机制造成本低,广泛用于生产制造设备;当然两者最终都有相似未来的发展趋势。

观测器与滤波器

by Mike杨

个人认为滤波器是意义是在我们能完整得到一组/多组含有随机噪声的观测值/测量值时,如何将噪声的影响最大化“剔除”。也就是我们如何从已有信息中提炼最正确的信息。
而观测器则是多在状态观测不可用/无法观测时,通过系统模型来建造一个结构去逼近/估计真实的系统状态。也就是一个无中生有的过程。
在结果上,由于噪声的随机性,我们并不能确定我们估计误差的收敛界是多少,但是我们能通过噪声的特性和滤波器的设计与结构获得误差的期望/方差。当你自己设计一个系统,并且通过设计合适的滤波器去实验/仿真的时候,你会发现真实的估计误差方差会真的收敛到由滤波器结构而决定的稳态方差上。
但是对于观测器的设定,我们更倾向于通过其误差的有界性去证明观测器的有效性和稳定性。你能通过李雅普诺夫函数分析到一个很充分的误差收敛上界,从而判断自己的准确性。

BLDC使用多级对+抗齿槽算法实现平滑转动;PMSM使用正弦波/马鞍波调制实现平滑转动

输出模拟电压有DAC肯定首选DAC输出。没有DAC的片子才会考虑用PWM通过低通滤波来产生模拟电压。PWM主要用在电力电子控制中比如电机控制、逆变器、UPS等。DAC输出模拟量,后级的线性功率放大是问题, 而 pwm 输出是开关量, 可以很简单高效地驱动大功率负载。当然PWM接低通滤波也可以直接输出模拟量了。

通常情况下,电机相电阻应该相等。若不相等,则表明电机内部存在问题,可能是线圈接触不良、绕组短路等原因。这些问题会导致电机运行不稳定,甚至损坏电机。

参考资料:
  1. STM32定时器三种中心对齐计数模式简介 - 知乎 (zhihu.com)—告知了TIM启用中心对齐模式以匹配算法
  2. 启用PWM互补输出HAL_TIMEx_PWMN_Start(),且输出值为1 - TIMx->CCR.
  3. DAC与PWM的区别、功能有何不同? - 单片机论坛,单片机技术交流论坛 - 21ic电子技术开发论坛

10.多种c语言代码的svpwm实现

SPWM:

CawFOC
DengFOC
foc-wheel-legged-robot/stm32-foc/software/USER/MagneticSensor.c at master · Skythinker616/foc-wheel-legged-robot (github.com)

SVPWM:

miniFOC/Software/foc/Hardware/Src/foc.c at main · HangX-Ma/miniFOC (github.com)
foc-wheel-legged-robot/stm32-foc/software/USER/BLDCMotor.c at master · Skythinker616/foc-wheel-legged-robot (github.com)
SimpleFOC
MiniFOC-
Odrive
Ti-SVGEN

波形不精细->角度步进太大

参考资料:

  1. IPMSM 方波注入无传感器FOC控制_方波高频注入-CSDN博客
  2. 【精选】三相永磁同步电机无感滑模观测控制TI源代码解析_smo滑模观测器算法c代码-CSDN博客
  3. SVPWM原理及编程实现(Ti的库)_ti svpwm-CSDN博客
  4. 永磁同步电机Matlab仿真(四)_matlab同步电机的vt是什么-CSDN博客
  5. 三角形接法永磁同步电机的FOC+SVPWM控制_同步电机 三角接-CSDN博客
  6. 【精选】FOC控制算法详解-CSDN博客
  7. SVPWM算法在低成本微控制器中的快速实现 - 嵌入式处理 - 技术文章 - E2E™ 设计支持 (ti.com)
  8. TMS320F28335: 对比SVGEN_DQ.H与SVGEN.H - C2000™︎ 微控制器论坛 - C2000 微控制器 - E2E™ 设计支持 (ti.com)
  9. svgen.h - C2000™︎ 微控制器论坛 - C2000 微控制器 - E2E™ 设计支持 (ti.com)

11.处理任务处理频率不合理导致的通信遗留问题

  • 尝试结果:
    修改读取角度参数为5ms一次(systick开启),主函数中可以稳定读取。
    需要修改tim2-FOC线程为8kHz。
    时间参数不对导致波形失真严重,抖动;
    限幅很厉害,力矩根本上不去。

失利于无法正常读取as5600角度导致电机闭环测试失败。遂去参考一些资料,得出结论是:

不建议在TIM中断中读取iic设备数据,特别是频率高于1kHz的情况。因此目前最好的改法应该是在定时器中添加标志,在主程序中执行收发,如果收发失败则恢复上一次接收数值,以减少异动。
miniFOC例程技巧 太多以致于无法改进,或者说SPI真的比iic快太多🥲

[3]说是定时器中断优先级顺序的问题,但是本项目没开iic中断的说。

有答主[1]分享iic总线驱动频率4kHz下采集MPU6050数据最快在5ms;
甚至[2]说

AS5600是IIC或者pwm通信,又不能在定时器中断里直接读iic数据,因为耗时太长了可能看门狗复位;

还好也有使用as5600的答主分享[4],不过看代码似乎是在主程序添加tim_flag标志。

用定时器1实现20ms中断一次,采集as5600编码器的计数值a并把数据作为上一次的值last_a,下一次进入中断把差值除以0.02即可得到每秒的计数值counter。counter / 4096 = n 转/秒。

参考资料:

  1. MPU6050需要多少时间测量一组数据,用的是PIC18F4550。_百度知道 (baidu.com)
  2. 【直流无刷电机】二、固定换相时间之调速_永遠亭Official的博客-CSDN博客
  3. I2C和定时器中断(定时器1) - VoidCC

12.工程情况报告

将gd32的minifoc移植到stm32上,通过采集iic设备,线程计算pwm,实现单路foc输出,并输出PWM、FOC角度速度、pid误差的参数到vofa上以供分析。

  • 实现过程:
    版本:
    双路移植->单路驱动移植->单路foc线程移植
    驱动参数:
    uart_DMA_460800
    iic_400k
    pwm_18kHz
    foc_12kHz(⚠与速度不匹配)
    speed_sys_200Hz
    pid_100Hz
    移植通信模块:
    通信缓冲区放到各文件下,方便移植
    提供寄存器等define、数据存储struct、通信应用协议functio
    iic设备移植,适配速率、数据位;
    foc算法移植:
    pwmN移植,适配互补输出
    熟悉foc参数计算:变换、扇区判断,扇区时间,foc-svpwm输出范围
    修改pid限幅
    根据自身硬件调整config参数适配filter和线程
    线程移植:
    执行速率匹配,剔除高耗时任务
    计算uart发送字节数,改善发送效率
    程序:
    初始化数据缓冲区
    初始化延时、
    初始化iic设备,uart设备
    初始化计算filter、pid数据结构
    初始化pwmN输出
    初始化foc相位、编码器零度
    开启foc、pid线程
    设置pid期望
    循环vofa输出foc参数

  • 存在问题:

  • svpwm波形正常,但是输出卡顿,疑似角度更新与pwm更新不匹配

  • 测试线程时间失败,HAL_GetTick()计时失败,返回0

  • 仅有力矩环正常输出,速度环、位置环异常无法收敛

  • 转动噪声大且发热快,疑似出现电机失步现象

  • vofa发送控制没时间实现

  • 双路效率一般,可能需要转rtos

### 回答1: FOC技术笔记是一本介绍磁场定向控制(FOC)技术的书籍,该技术被广泛应用于电机驱动和控制系统中。本书新修版增加了一些新的内容,使其更加实用和易于理解。 本书首先介绍了FOC技术的基本原理、工作原理和控制方法。然后,作者详细讲解了FOC技术的各个方面,包括磁链定向、PI控制器、换相时间和磁栅编码器等。同时,作者还介绍了FOC技术在电机驱动系统中的应用,并提供了一些实际案例,帮助读者更好地理解和应用该技术。 除此之外,本书还介绍了FOC技术的未来发展趋势,包括使用新型半导体器件、软件控制和智能化控制的发展方向。本书还提供了一些有用的参考文献和相关资源,帮助读者更深入地学习和掌握FOC技术。 总之,FOC技术笔记的新修版是一本非常实用的书籍,适合电机工程师、研究人员和学生阅读和学习。通过学习本书,读者可以更好地理解FOC技术的基本原理和应用,为电机驱动系统的设计和应用提供更好的支持。 ### 回答2: FOC技术笔记-新修版包含了FOC控制的基本概念和技术,以及FOC在电机控制方面的应用。全书分为十二章,主要内容涵盖了电机模型、矢量控制、PID控制、空间矢量调制、磁阻电动机和无刷直流电机等多种类型电机的FOC控制方法,并结合实例详细介绍了各类电机FOC控制的具体实现方法。 此书旨在为读者提供一种深入理解FOC技术及其在电机控制方面应用的新途径。读者可通过本书了解到FOC技术的基本思想和原理,可以掌握FOC控制技术的全流程,并逐步熟悉FOC控制器的编程调试方法。此外,本书还介绍了一些应用实例,以帮助读者更好地理解和应用FOC技术。 总之,FOC技术笔记-新修版具有较高的实用性和可操作性,可以为进一步深入研究FOC技术的工程师和学生提供帮助,也为广大电机控制爱好者提供了一定的帮助。同时,该书也是一本值得收藏的电机控制领域的参考书籍。 ### 回答3: FOC技术笔记是一本关于电机控制技术方面的教材。新修版相较于旧版,增加了许多实用内容,更贴近实际应用。 新修版FOC技术笔记对基础知识进行了详细的介绍,如电机模型、磁场定向控制、三相控制等。同时,它还介绍了许多高级的控制技术,比如预测控制、自适应控制等。这些内容对于电机控制工程师来说非常实用。除了技术方面的内容,新修版还介绍了一些案例分析,让读者更好地了解电机控制在实际应用中的应用。 除此之外,新修版FOC技术笔记还包含了一些新的内容,如无感矢量控制、无传感器FOC控制等,这些内容对于新能源汽车等领域具有重要意义。 总之,新修版FOC技术笔记是一本非常实用的书籍,我相信它会为电机控制工程师提供很多帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值