ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

第一次用 CAN 控制电机:STM32F103 驱动 M3508 与 PID 调速记录

第一次用 CAN 控制电机:STM32F103 驱动 M3508 与 PID 调速记录

这是我第一次把 CAN 通信和 PID 用到实际电机控制里的工程。主控是 STM32F103C8,使用标准库开发,搭配 TJA1050 CAN 收发器模块,通过电调控制 DJI M3508 电机。程序读取转速反馈,再由速度 PID 计算电流指令发给电调,调试时用匿名上位机修改参数、观察曲线。

调试中让我印象最深的是反馈滤波:一开始电机空载运行,转速波动,难以收敛到目标值;加入一阶低通滤波后,收敛情况有了改善。通过这次调试,我开始理解速度反馈的处理会怎样影响 PID 的控制效果。

一、先把 CAN 收发跑通

STM32 通过 CAN 电调控制电机:发送电流指令,接收转速、角度和温度等反馈。主控侧使用 TJA1050 模块,将 PA12、PA11 的逻辑信号转换成 CANH、CANL,再接入电调总线。

项目工程中的配置用途
主控与工具链STM32F103C8、标准库、Keil ARMCC5主循环计算速度 PID
电机 / CAN 收发器DJI M3508 / TJA1050 模块电机执行与 CAN 物理层通信
CAN1 TX / RXPA12 / PA11连接 CAN 收发器 TXD / RXD
CAN 模式与速率正常模式,1 Mbit/s;CAN 外设时钟为 36 MHz与电调交换控制和反馈报文
USART1 TX / RXPA9 / PA10,115200、8N1连接匿名上位机
OLED SCL / SDAPB6 / PB7,软件模拟接口显示 PID 参数与输出

接线时将电调和电机固定好,断电连接电源与总线,并按实际 CAN 布线配置终端电阻。CANH、CANL 接收发器的总线侧,电机功率线和供电走电调。

一帧控制指令怎么对应到电机

程序使用标准数据帧,控制报文 ID 为0x200,8 个字节分成四组,每两个字节放一个电机的电流指令,高字节在前。

报文 / 字节含义本工程的使用方式
发送 ID0x200,Byte 0~1电机 1 的电流指令放入速度 PID 输出
同帧 Byte 2~7电机 2~4 的电流指令当前发送 0
接收 ID0x201ID 为 1 的电调反馈读取转速供速度环使用
接收 ID0x202~0x204其他三个电调反馈保留对应的数据结构

接收中断先把报文交给电机模块,电机模块根据 ID 选择数据结构,再从字节数组解析出角度、转速、电流和温度。这样 CAN 模块负责收发,电机模块负责理解报文,主循环只需要取转速来计算。

电调协议中的转速单位是转子 RPM。对减速电机,如果要显示输出轴转速,还需要结合实际减速比换算。

二、把转速反馈接进 PID

CAN 通信跑通以后,速度环的处理顺序就是:读取转速 → 低通滤波 → 与目标比较 → 计算 PID → 发送电流指令。

工程用的是位置式 PID:比例项由当前误差计算,积分项逐次累加,微分项使用本次与上次误差之差。积分项和总输出都设置了限幅。

配置初始值说明
目标转速1000 RPM对应反馈中的转子转速
Kp / Ki / Kd4 / 0.1 / 0.1后续可由上位机修改
积分项限幅±2000限制累加的积分输出
总输出限幅±2000输出为电调电流指令计数

主循环中的关键调用是:

out=PID_Calc(&motor_speed_pid,target_speed[0],real_speed[0]);Motor_cmd_chassis(out,0,0,0);

这里目标与反馈是转速,PID 算出的结果则作为电流指令发送。转速低于目标时,控制器根据误差调整输出,再用下一次反馈修正,这样就形成了闭环。

PID 放在主循环中执行,一轮循环包括控制计算、串口发送、OLED 显示和末尾的Delay_ms(2)。积分项按调用次数累加,微分项直接取相邻两次误差之差,执行周期会影响这两项的作用大小;后续修改串口发送量或显示频率时,PID 参数也需要随之检查。

三、空载调试时的波动与低通滤波

当时电机空载运行,用匿名上位机调 PID 时,转速曲线一直在晃,很难收敛到目标值。后来在速度反馈进入 PID 之前加了一阶低通滤波,收敛情况改善了不少。这个过程让我注意到,调速度环时,反馈信号的处理和 PID 参数一样值得关注。

一阶低通是怎么处理转速的

工程使用的滤波系数是0.2,当前读数占 20%,上一次滤波结果占 80%:

y k = 0.2 x k + 0.8 y k − 1 y_k=0.2x_k+0.8y_{k-1}yk​=0.2xk​+0.8yk−1​

其中x k x_kxk​是这次读到的转速,y k y_kyk​是处理后送入 PID 的转速。对应代码如下:

filter_speed[i]=FILTER_ALPHA*motor->speed_rpm+(1-FILTER_ALPHA)*filter_speed[i];real_speed[i]=filter_speed[i];

举个计算例子:如果上次滤波结果是 1000 RPM,这次读到 1100 RPM,经过这一步以后,得到的是 1020 RPM。单次读数的变化被缓和,PID 接收到的反馈也随之更平滑。

real_speed同时传给 PID 和匿名上位机,所以控制器使用的反馈与上位机显示的转速,都经过了这一步滤波。

滤波系数决定了每次采纳多少新读数:系数小一些,反馈更平滑,但跟随转速变化也更慢。这里取0.2,让反馈逐步过渡,PID 根据处理后的转速计算输出。

通过这次调试理解滤波对控制的作用

速度反馈直接参与误差计算,反馈中的快速波动也会传到 PID 输出中。这份 PID 的微分项使用相邻两次误差之差,对这种变化尤其敏感。加入低通滤波后,较快的反馈波动被减弱,控制器根据更平滑的反馈调整电流指令。

对我来说,这次调试把滤波和闭环控制联系了起来:除了调整 Kp、Ki、Kd,还要考虑送进控制器的反馈信号。滤波放在反馈通路中,系数的选择也就成为速度环调试的一部分,需要在平滑程度和响应速度之间取舍。

用上位机调参数,比反复改代码方便

工程按匿名 V7 协议组织串口通信,上报四组目标与反馈数据,并接收 PID 参数和目标转速。参数 1~3 分别映射到 Kp、Ki、Kd,代码将收到的值除以 100,例如参数值 300 对应 Kp=3。

这样修改目标转速和 PID 参数时,就可以直接在上位机操作,观察曲线变化,不必每改一个参数都重新编译下载。程序中,串口模块解析参数,主循环更新设定值,PID 模块计算输出,最后通过 CAN 发给电调。

四、这次调试的收获

第一次通过 CAN 控制 DJI M3508,我熟悉了帧 ID、反馈解析、速度 PID 和匿名上位机调参。空载调试中遇到的收敛问题,则让我理解了反馈滤波在控制中的作用:从电调读回转速,到处理反馈、计算输出,这一整条链路都会影响速度环的表现。
完整工程与使用说明:GitHub:STM32 CAN 控制 M3508 速度环

协议参考:RoboMaster C620 电调官方使用说明。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进