1. 硬件配置与方案选择在开始双电机控制之前我们需要先了解ESP32的硬件特性和常见的驱动方案。ESP32作为一款功能强大的微控制器内置双核处理器、丰富的外设接口和灵活的PWM输出非常适合用于电机控制场景。我实际测试过多种方案发现硬件配置的选择会直接影响后续的编程复杂度和控制效果。目前主流的方案有两种ESP32drive-D和SimpleFOCShield。ESP32drive-D采用了非对称电路设计M1接口使用三个独立的使能引脚这与PowerShield V0.2大功率驱动板的控制方式一致而M2接口的使能引脚则是并联的类似于SimpleFOCShield V2.0.4的设计。这种设计虽然灵活但在调试时需要特别注意引脚配置的差异。我在第一次使用时就在这里栽过跟头电机死活不动后来才发现是使能引脚配置错了。SimpleFOCShield的方案相对简单只需要一个使能引脚通常定义为IO32。但要注意的是SPI和I2C2的引脚有复用不能同时使用。在实际连接时两块SimpleFOCShield可以堆叠使用具体引脚对应关系如下ESP32-DevKitC SimpleFOCShield 3 5 2 6 9 14 6 32 8 35 10 34 5 21 16 33 17 10 4 7 1 9 3V3 VCC GND GND对于编码器的连接AS5600和AS5047P的接线方式有所不同。AS5600使用I2C接口接线相对简单而AS5047P需要SPI接口接线时要特别注意MOSI、MISO、SCLK和SS的对应关系。我曾经因为接反了MOSI和MISO导致编码器读数异常调试了半天才发现问题所在。2. 双I2C接口配置实战双电机控制的一个关键难点在于如何正确配置和使用ESP32的双I2C接口。ESP32有两个I2C接口Wire和Wire1而且这两个接口的引脚可以灵活配置到任意GPIO上。这个特性非常有用但在实际使用中也容易出现问题。首先需要明确的是I2C接口的配置不能使用标准的begin()函数而应该使用setPins()和setClock()函数。这是因为在双电机控制场景下我们需要精确控制每个I2C接口的引脚分配和时钟频率。我在项目中就遇到过因为时钟频率设置不当导致的通信不稳定问题后来通过调整setClock()参数解决了。具体配置步骤如下包含必要的头文件#include Wire.h #include SimpleFOC.h初始化第一个I2C接口WireWire.setPins(SDA1_PIN, SCL1_PIN); Wire.setClock(400000); // 400kHz Wire.begin();初始化第二个I2C接口Wire1Wire1.setPins(SDA2_PIN, SCL2_PIN); Wire1.setClock(400000); Wire1.begin();在实际调试时建议先用两个编码器测试I2C接口是否正常工作。可以通过读取编码器的角度值来验证通信是否稳定。我通常会编写一个简单的测试程序连续读取两个编码器的值并打印到串口观察数据是否连续、稳定。3. 双电机驱动实现3.1 速度模式控制速度模式是最常用的控制方式特别适合需要精确转速控制的场景比如机械臂关节或移动平台的差速转向。在SimpleFOC中实现双电机速度控制需要以下几个步骤首先需要为每个电机创建独立的FOC对象BLDCMotor motor1 BLDCMotor(7); BLDCMotor motor2 BLDCMotor(7);然后分别配置两个电机的参数包括极对数、编码器、PWM设置等。这里有个小技巧可以先配置好一个电机然后复制配置到第二个电机再修改差异部分。这样可以避免重复劳动我在实际项目中都是这么做的。速度控制的核心是PID参数的调节。SimpleFOC提供了VelocityPID结构体来配置速度环参数motor1.PID_velocity.P 0.2; motor1.PID_velocity.I 20; motor1.PID_velocity.D 0; motor1.LPF_velocity.Tf 0.01; motor2.PID_velocity.P 0.2; motor2.PID_velocity.I 20; motor2.PID_velocity.D 0; motor2.LPF_velocity.Tf 0.01;上传程序后可以通过串口发送指令控制电机。例如控制A电机A6.28表示6.28rad/s约1圈/秒控制B电机B20表示20rad/s在实际调试时建议先用较低的转速测试观察电机运行是否平稳再逐步提高转速。我遇到过因为PID参数不当导致的电机震动问题通过调整I参数解决了。3.2 其他控制模式除了速度模式SimpleFOC还支持力矩模式和角度模式以及它们的混合模式。这些模式在双电机协同控制中也非常有用。力矩模式适合需要精确控制输出力矩的场景比如机械臂抓取物体时motor1.torque_controller TorqueControlType::voltage; motor2.torque_controller TorqueControlType::voltage;角度模式则适合需要精确定位的应用motor1.controller MotionControlType::angle; motor2.controller MotionControlType::angle;混合模式可以结合速度和位置控制实现更复杂的运动轨迹。我曾经在一个项目中需要电机先快速到达某个位置然后保持精确的速度就是通过混合模式实现的。切换控制模式时记得要同时调整对应的PID参数。不同模式对PID参数的要求差异很大需要反复调试才能达到最佳效果。我的经验是先从官方示例的参数开始然后根据实际表现逐步调整。4. 双电机协同算法4.1 速度同步控制在机器人或精密仪器中经常需要两个电机保持同步运行。比如移动平台的差速转向或者机械臂两个关节的协调运动。实现这种同步控制需要考虑以下几个方面首先需要建立一个主从关系。通常选择一个电机作为主电机另一个作为从电机。主电机按照设定的速度运行从电机则跟随主电机的速度。代码实现上可以这样float master_speed target_velocity; float slave_speed master_speed * ratio; // ratio是主从速度比 motor1.move(master_speed); motor2.move(slave_speed);其次要考虑两个电机之间的耦合效应。在实际系统中两个电机可能存在机械耦合一个电机的运动会影响另一个。我曾经遇到过一个电机加速时另一个电机速度波动的问题。解决方法是在控制算法中加入交叉补偿项。4.2 位置跟随控制位置跟随是另一种常见的协同模式比如让一个电机的位置跟随另一个电机的位置变化。这在仿生机器人中特别有用。实现位置跟随的关键是建立位置映射关系。可以通过编码器获取两个电机的位置然后计算跟随误差float master_position motor1.shaft_angle; float desired_slave_position master_position * gear_ratio offset; float position_error desired_slave_position - motor2.shaft_angle; // 使用PID控制器计算修正速度 float correction_speed position_pid(position_error); motor2.move(correction_speed);在实际应用中还需要考虑机械结构的限制比如关节角度范围、最大速度等。我曾经因为没加限制导致电机试图超出机械限位产生了很大的冲击力。后来在代码中加入软限位保护解决了这个问题。5. 调试技巧与常见问题5.1 硬件调试技巧在调试双电机系统时硬件问题是首先要排除的。以下是我总结的几个实用技巧电源问题确保电源功率足够驱动两个电机。我曾经因为电源功率不足导致电机在加速时电压骤降系统重启。接地问题良好的接地可以减少干扰。建议使用星型接地所有地线汇集到电源地。信号完整性电机驱动信号线要尽量短必要时可以加终端电阻。PWM信号线过长会导致波形畸变影响控制效果。编码器连接编码器线最好使用双绞线减少干扰。AS5047P等磁性编码器要确保安装间隙合适。5.2 软件调试技巧软件调试同样重要以下是我常用的方法分步调试先让单个电机工作正常再添加第二个电机。不要试图一次调试整个系统。串口打印在关键位置添加串口打印监控变量变化。比如电机速度、位置、电流等。可视化工具使用SimpleFOC Studio等工具实时观察电机状态比单纯看串口数据直观得多。参数记录调试过程中记录每次参数修改和效果方便回溯和优化。5.3 常见问题解决在实际项目中我遇到过各种奇怪的问题这里分享几个典型案例电机抖动可能是PID参数不合适特别是I值太大。尝试减小I值增加D值。编码器读数跳变检查编码器接线是否牢固电源是否稳定。AS5600需要稳定的3.3V供电。通信中断I2C通信不稳定时可以尝试降低时钟频率或者加上拉电阻。电机不转首先检查使能信号然后测量PWM输出。有时候是电机相位接反了。经过多次项目实践我发现双电机系统90%的问题都出在硬件连接和基础配置上。真正到控制算法层面的问题反而比较少。所以耐心做好基础工作非常重要。