SimpleFOC实战:双电机协同控制与版本避坑指南

📅 发布时间:2026/7/13 10:15:01 👁️ 浏览次数:
SimpleFOC实战:双电机协同控制与版本避坑指南
1. 硬件准备与连接为双电机协同打好地基想玩转双电机协同控制第一步就是把硬件平台搭稳当。这就像盖房子地基不牢后面写再多代码也白搭。我这次用的核心板和原始文章里一样是经典的Arduino UNO搭配两块SimpleFOCShield V2.0.3驱动板。电机选了两个带磁编码器的云台电机这种电机内部集成了AS5600这类磁编码器省去了额外安装编码器的麻烦精度也足够。电源方面一个12V的直流电源给两个驱动板供电再准备一根方口USB线给UNO供电和通信齐活。硬件连接是第一个小关卡但理清了逻辑就很简单。核心原则就一个让Arduino UNO能独立控制两个电机驱动板的所有引脚。SimpleFOCShield设计得很巧妙它通过背面的跳线帽来选择使用UNO的哪一组PWM引脚。对于双电机控制我们需要把两块驱动板配置到不同的引脚组上。具体操作如下第一块驱动板我们把背面的跳线帽插在9, 5, 6, 8这组引脚上。这组引脚对应的是UNO的定时器1专门用来生成PWM信号。第二块驱动板跳线帽则插在3, 10, 11, 7这组引脚上这对应的是定时器2。这一步至关重要它确保了Arduino可以同时、独立地产生两路PWM信号去驱动两个电机不会互相干扰。如果两块板子跳线一样那代码就没办法区分它们了。接下来是编码器接线。我们用的云台电机自带AS5600编码器输出的是模拟信号。UNO板上有A0到A5多个模拟输入口正好够用。这里有个细节需要注意编码器的供电。UNO板可以提供两路5V输出我们可以分别用它们给两个编码器供电避免共地干扰。接线时将第一块驱动板跳线9,5,6,8对应的电机编码器输出线接到UNO的A0模拟引脚。第二块驱动板跳线3,10,11,7对应的编码器则接到A2模拟引脚。电源和地线对应接好即可。为什么要这么对应因为在后续的代码里我们会根据这个硬件连接关系来初始化编码器对象接线乱了程序就读不到正确的角度信息。最后是总装。先把两块SimpleFOCShield驱动板像叠罗汉一样堆叠在Arduino UNO上注意引脚对齐。然后用USB线连接电脑和UNO。12V电源的正负极分别接到两块驱动板的“TB_PWR”端子这里可以并联接入。电机的三根相线U, V, W接到对应驱动板的电机输出端。编码器的插头插到驱动板预留的排母上。全部接好后建议再检查一遍特别是电源正负极接反了可能会烧坏驱动芯片。硬件连接看似繁琐但只要你按照“跳线 - 编码器 - 电源 - 电机”这个顺序捋一遍就能搭建出一个可靠的双电机控制实验平台。2. 软件环境搭建与版本避坑避开v2.2.2的“天坑”硬件连好了接下来就是软件环境。这里我要重点强调一个超级大坑也是很多新手朋友最容易栽跟头的地方SimpleFOC库的版本选择。根据我多次实测和社区反馈如果你想做双电机控制绝对不要使用SimpleFOC库的v2.2.2版本这个版本在处理多电机实例时存在一个隐蔽的Bug会导致第二个电机初始化失败、控制指令紊乱或者两个电机互相影响表现就是电机抽搐、不转或者行为诡异。那用什么版本呢经过反复测试v2.1.1版本是目前对双电机支持最稳定、兼容性最好的选择。所以我们的第一步就是在Arduino IDE中安装正确版本的库。如果你已经安装了其他版本请先卸载。打开Arduino IDE点击“项目” - “加载库” - “管理库”在搜索框输入“SimpleFOC”。在库列表中找到“Simple FOC”这个库不要直接点安装点击它右下角的版本选择下拉菜单手动选择2.1.1版本然后再点击“安装”。这样就确保了我们使用的是经过验证的稳定版本。安装好库之后我们来打开示例程序。在Arduino IDE中点击“文件” - “示例” - 滚动找到“Simple FOC” - 选择“motors”文件夹下的“dual_motor_control”。这个就是官方提供的双电机控制例程是我们学习的绝佳起点。但是这个例程不能直接拿来就用因为它默认配置的是带ABZ正交输出编码器的电机而我们用的是模拟输出的AS5600编码器。直接上传电机是不会有任何反应的。所以我们需要根据手头的硬件修改这个例程。主要修改两个地方电机极对数和编码器类型。云台电机的极对数通常是7对极也就是14个磁极这个参数需要准确它直接关系到电角度和机械角度的换算。在代码开头找到定义电机对象的语句比如BLDCMotor motor1 BLDCMotor(7);这里的参数“7”就是极对数确认它是否符合你的电机。接着是重头戏修改编码器配置。我们需要把默认的MagneticSensorSPI或MagneticSensorI2C换成MagneticSensorAnalog。具体代码修改如下。对于电机1假设接在A0// 替换原来的编码器初始化代码 MagneticSensorAnalog sensor1 MagneticSensorAnalog(A0, 14, 1020); // 参数解释A0是引脚14是磁极数注意不是极对数1020是ADC最大值校准值根据实测调整对于电机2假设接在A2MagneticSensorAnalog sensor2 MagneticSensorAnalog(A2, 14, 1020);然后在setup()函数中用motor1.linkSensor(sensor1);和motor2.linkSensor(sensor2);将传感器与电机对象关联起来。这些修改确保了库能正确读取我们电机的绝对角度。改完后可以先点击“验证”编译一下看看有没有语法错误。由于我们打开的是示例文件Arduino IDE默认是只读的如果想保存自己的修改记得点击“文件” - “另存为”创建一个新的工程文件。3. 基础控制模式实战从力矩到速度程序修改好就可以上传到UNO板了。上传成功后打开串口监视器波特率通常为115200。你会看到初始化信息开始滚动库会尝试对齐电机的电角度和机械角度。当看到“Motor 1 ready!”和“Motor 2 ready!”的提示时恭喜你初始化成功了此时两个电机应该会开始缓慢地来回转动这是库在运行默认的“力矩控制”模式。力矩控制模式是最直接的模式。在这个模式下我们给电机施加的是一个“力”的指令单位是电压V。在初始化完成的串口监视器里你可以输入指令来交互。例如输入“A1.5”然后回车就是给电机1施加1.5V的电压指令。你会发现电机1的转速立刻发生了变化。同理“B2.0”是给电机2施加2.0V的指令。你可以分别设置不同的值观察两个电机以不同的转速旋转这就是独立的开环力矩控制。如果你用手去捏住电机轴会感觉到电机在“较劲”试图维持这个力矩输出捏得越紧电机电流越大如果有电流表可以观察到直到你捏停它。这个模式非常适合需要恒定力输出的场景比如机器人的抓握。接下来我们试试更常用的速度控制模式。切换到速度模式需要在代码里进行配置。在setup()函数中找到motor1.initFOC()和motor2.initFOC()语句之前添加PID参数设置和模式切换。SimpleFOC库内置了速度PID控制器我们需要激活它。// 配置电机1的速度PID控制器参数P, I, D, 输出限幅速度测量滤波时间常数 motor1.PID_velocity.P 0.2; motor1.PID_velocity.I 5; motor1.PID_velocity.D 0; motor1.PID_velocity.output_ramp 1000; // 输出变化率限制 motor1.LPF_velocity.Tf 0.01; // 低通滤波时间常数 motor1.velocity_limit 20; // 速度限制单位rad/s // 将控制模式设置为速度控制 motor1.controller MotionControlType::velocity; // 对电机2进行同样的配置参数可以根据需要调整成不一样的值 motor2.PID_velocity.P 0.2; // ... 其他参数 motor2.controller MotionControlType::velocity;这些PID参数比例P、积分I、微分D需要根据你的具体电机和负载进行调试没有万能值。参数不合适电机可能会振荡P太大、响应慢P太小或者有静差I不够。改好后重新上传程序。初始化后电机会开始以某个初始速度旋转在例程里这个初始目标速度可能是2 rad/s。现在你再通过串口发送指令“A5”或“B-3”意思就变成了“电机1请以5 rad/s的速度旋转”和“电机2请以-3 rad/s的速度反转”。电机内部的PID控制器会拼命工作让实际转速紧紧跟随你的指令即使负载发生变化也会努力维持速度恒定。这个模式在需要精确转速同步的应用里比如 conveyor belt传送带或者云台的平滑转动就非常有用。4. 高级玩法混合控制与双机协同策略掌握了独立的速度和力矩控制我们就可以玩些更高级的了混合控制与协同策略。所谓混合控制就是让两个电机运行在不同的控制模式下各司其职配合完成更复杂的任务。这在机器人学里非常常见。举个例子我们可以让电机1运行在速度模式负责维持一个恒定的旋转速度而电机2运行在力矩模式负责输出一个恒定的阻力或辅助力。想象一个简单的卷扬机场景电机1速度模式负责匀速收起绳子电机2力矩模式则可以模拟一个恒定的负载比如重物的重力。代码实现上就是在初始化时分别设置两个电机的controller变量为MotionControlType::velocity和MotionControlType::torque。上传程序后通过串口分别给它们发送不同单位的指令速度单位rad/s力矩单位V就能看到它们以完全不同的“性格”在运转。一个追求速度稳定一个追求力矩恒定。但真正的“协同控制”远不止于此。它意味着两个电机的运动是相互关联、有共同目标的。这就需要我们在上层逻辑中编写协调算法。SimpleFOC库负责底层的高性能电机控制而上层的协同逻辑则需要我们在loop()函数中实现。一个经典的协同场景是“主从跟随”让电机2的位置或速度实时跟随电机1。我们可以尝试一个简单的速度跟随。思路是在每次循环中读取电机1的实际速度将这个速度值或许乘以一个比例系数直接设置为电机2的目标速度。这样无论我们如何控制电机1电机2都会像影子一样跟随它。void loop() { // 必须执行的核心FOC更新函数 motor1.loopFOC(); motor2.loopFOC(); // 主从协同逻辑电机2的速度跟随电机1 float master_speed motor1.shaft_velocity; // 获取电机1的实际速度 float follow_speed master_speed * 0.8; // 从机以主机80%的速度跟随可调 motor2.move(follow_speed); // 将此速度设置为电机2的目标 // 电机1的目标速度可以由串口指令或其他逻辑设定 motor1.move(target_velocity_motor1); // 当然你也可以实现更复杂的关系比如位置同步、力矩互补等 }在这个框架下你可以发挥想象力实现各种协同策略。比如让两个电机输出大小相等、方向相反的力矩模拟一个“拧毛巾”的动作或者让一个电机做正弦运动另一个电机做余弦运动实现画圆轨迹。关键在于SimpleFOC库提供了稳定、实时的底层电机状态位置、速度、力矩获取和控制接口让我们可以专注于上层应用逻辑的编写而不用操心复杂的磁场定向控制算法实现。这大大降低了双电机协同应用的门槛。5. 调试技巧与常见问题排查实战过程中遇到问题才是常态。这里我分享几个自己踩过坑后总结的调试技巧和常见问题排查方法希望能帮你快速定位问题。问题一电机完全不动或者初始化失败。这是最让人头疼的情况。首先检查硬件连接特别是编码器接线和供电。用万用表测量一下编码器的输出引脚接A0/A2的那根线电压在用手缓慢转动电机轴时电压应该在0-5V之间平滑变化。如果没有变化可能是编码器没供电或者损坏。其次确认库版本是v2.1.1。然后检查代码中的极对数和磁极数设置是否正确这两个参数设错电机无法对齐。最后打开串口监视器观察初始化日志。如果卡在“MOT: Align sensor”这一步多半是传感器读数有问题重点检查上述硬件和参数。问题二电机抖动、振动或发出噪音。这通常与控制参数有关。在力矩或速度模式下如果PID参数特别是比例增益P设置得过高会导致系统不稳定产生振荡。解决方法是从小到大慢慢调整P值。先把I和D设为0逐渐增加P直到电机能启动且响应迅速但又不产生剧烈抖动为止。如果电机在低速时抖动明显还可以尝试增加速度低通滤波器的Tf值滤掉一些高频噪声。另外确保电源功率充足12V电源能否提供两个电机同时工作所需的电流电压是否稳定电源功率不足也会导致电机失步和抖动。问题三两个电机互相干扰一个动另一个也跟着抽动。这强烈指向了版本Bug或者硬件干扰。首先再次百分之百确认你用的是SimpleFOC v2.1.1库。如果版本没错那么检查硬件上是否存在干扰。两个电机的电源线、编码器线最好分开走线避免平行紧贴。可以尝试给每个驱动板的电源输入端并联一个大的电解电容比如1000uF来滤除电源噪声。在软件上确保两个电机对象的初始化、FOC更新函数调用都是独立的没有共用某个全局变量导致耦合。问题四控制响应慢或者有稳态误差。响应慢可以尝试增大速度PID中的P值或者减小输出变化率限制output_ramp。如果存在稳态误差比如给定速度10 rad/s实际只能到9.5 rad/s就需要引入积分项I。慢慢增加I值直到稳态误差被消除但要注意I值太大会引起超调和振荡。调试PID是个耐心活没有捷径最好一次只调一个参数观察现象做好记录。善用串口调试SimpleFOC库的串口命令终端是一个强大的调试工具。除了发送控制指令你还可以通过输入“M”来查看所有电机的状态包括目标值、实际值、PID输出等。这比盲猜要直观得多。调试时不妨让电机先以开环模式运行motor.controller MotionControlType::torque且不调用initFOC确认硬件和基本通信没问题后再切入闭环模式一步步细化参数。记住耐心和细致的观察是解决所有嵌入式问题的法宝。