做伺服电机控制,硬件选型是第一步也是最关键的一步。我这次用的是STM32F302K8U6做主控,搭配L6205D驱动芯片,这个组合在小型伺服电机控制中性价比很高。先说主控选型,STM32F302系列自带FPU和DSP指令集,跑FOC算法很合适。K8U6这个型号虽然引脚少,但对我们这个项目完全够用,三相PWM、ADC采样、I2C通信这些关键外设都有。
驱动芯片选的是L6205D,这个芯片最大的优势是集成了MOS管和死区控制,PCB设计能省不少事。不过要注意的是它只能做单电阻采样,因为每两个MOS管共用一个电流采样引脚。实测下来,单电阻采样在中小功率电机上完全够用,但大功率电机还是建议用三电阻方案。
电流采样电路设计有几个坑要特别注意。首先是运放电路,我一开始按照常规设计加了偏置电压,结果发现采样值总是偏高。后来发现L6205D的输出特性比较特殊,去掉偏置电阻反而更准。运放放大倍数也要根据实际电流范围调整,我最后用的反馈电阻是1kΩ,放大倍数控制在20倍左右。
编码器部分用了TLV493D磁感应芯片,这个方案特别适合自制系统。它通过I2C接口输出XYZ三轴磁场数据,配合CORDIC算法就能算出转子角度。实测精度能达到12位,完全满足位置控制需求。不过要注意I2C必须开DMA,否则会影响FOC的执行频率。
用CubeMX配置FOC项目时,定时器设置是重中之重。TIM1要配置成中央对齐模式3,这样上下计数时都能触发中断。单电阻采样的关键是要在PWM周期内完成两次采样,我通过TRGO2触发ADC,在通道5和6的上升沿设置采样点。
ADC配置有个容易忽略的细节是对齐方式。ST官方库默认用左对齐,但我的电流采样值都是正值,改成右对齐后数据处理更方便。校准ADC也很重要,上电后一定要执行HAL_ADCEx_Calibration_Start(),不然采样误差能差出10%去。
I2C配置要注意时序参数。TLV493D要求快速模式(400kHz),上升时间不能超过300ns。我在CubeMX里把I2C时钟设为48MHz,然后根据芯片手册计算出的参数配置:
c复制hi2c1.Init.Timing = 0x00303D5B; // 400kHz with 48MHz clock
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
串口配置建议关闭中断,直接在主循环里轮询。实测发现如果串口中断优先级比ADC中断低,会出现数据丢失;如果优先级设高了,又会影响PWM波形。最后我用了简单的协议解决粘包问题,每个数据包加头尾标志。
移植FOC算法时最大的挑战是STM32F302K8U6不在MCSDK支持列表里。我的做法是用STM32F302R8的模板生成代码,然后手动移植。重点要改这几个文件:
电流环校准要注意顺序:
角度校准我设计了个自动流程:让电机空载慢转一圈,同时记录磁编码器读数。通过对比理论位置和实际位置,计算出角度偏差并存入Flash。这个校准值每个电机都不一样,所以要用STM32的Flash模拟EEPROM功能保存。
ADC采样数据处理有个坑要注意。官方库默认用Q15格式处理电流值,但单电阻采样的电流都是正值。我的解决方案是把ADC改为右对齐,然后在R1F30X_GetPhaseCurrents函数里对结果左移3位:
c复制pStator_Currents->a = (int16_t)((hPhaseA * 8) >> 1);
pStator_Currents->b = (int16_t)((hPhaseB * 8) >> 1);
位置环设计我跳过了速度环,直接用位置误差计算Iq参考值。核心结构体是这样的:
c复制typedef struct {
PID_Handle_t *PIPos;
int16_t hSetPosition; //目标位置
int16_t hStartPosition; //起始位置
int16_t hCurPosition; //当前位置
int16_t hError; //位置误差
int16_t hMaxTorque; //最大转矩
uint16_t hCurIndex; //S曲线索引
uint16_t hStep; //步长时间
uint8_t bIsChanging; //位置切换标志
} PosControl_Handle_t;
直接PID控制的问题是加减速不平稳,电机启动时有抖动。我试过几种方案后,最终选择S曲线算法。但标准S曲线计算量太大,我改成了定点查表法:
实测下来,这种方案在STM32F302上执行时间小于50us,完全能满足1kHz的位置环频率要求。电机转动过程非常平滑,定位精度能达到±0.5度。
PID参数调节有几点经验:
调试FOC系统时,电流波形是最重要的诊断工具。我用的是Saleae逻辑分析仪抓取ADC采样值,发现几个典型问题:
编码器数据异常时,先用I2C抓包工具看原始数据。TLV493D的XYZ值应该在±100mT范围内,如果某个轴数据异常,可能是磁铁安装偏心。我写了个简单的角度验证程序:
c复制void CheckAngle(void)
{
int32_t x = GetMagneticX();
int32_t y = GetMagneticY();
angle = atan2(y, x) * 180 / PI;
printf("Real angle: %d\r\n", angle);
}
电机不转的常见原因:
上位机调试我用了QT写了个简单界面,主要监控三个数据:
经过几轮优化,我的微型伺服系统达到了这些指标:
代码优化有几个关键点:
电源设计要注意瞬态响应。电机启动时电流很大,我在电源输入端加了470uF电解电容和0.1uF陶瓷电容并联。PCB布局也有讲究:
温度保护是很多人忽略的。我加了简单的软件保护:
c复制if(MC_Interface_GetTemp() > 80) {
PWMC_SwitchOffPWM(pwmcHandle);
Error_Handler();
}
最后说说抗干扰设计。电机运行时会对MCU产生干扰,我的应对措施: