
一、 主要特点
该系统的特点围绕“同步”与“平滑”两个核心,体现了高精度运动控制的精髓。
轨迹同步与电子齿轮/凸轮
核心特点:系统超越了简单的“同时启动/停止”,实现了复杂的轨迹同步。这包括:
电子齿轮:从轴的位置严格地、按一定比例跟随主轴的位置变化。比例可以是固定值,也可以是动态变化的。
电子凸轮:从轴与主轴的位置关系遵循一个预定义的、非线性的函数关系(如正弦曲线、凸轮曲线)。
专业视角:这通过软件算法取代了传统的机械齿轮和凸轮机构,实现了极高的灵活性和可重构性。主从轴之间的相位和比例关系可以通过程序实时修改,无需改变任何硬件。
前瞻性加速度管理
核心特点:系统在规划运动轨迹时,并非简单地从起点A到终点B,而是会预先计算整段路径,并施加加速度规划,最常见的是使用S曲线加速度。
专业视角:与简单的梯形速度曲线(加速度突变导致冲击)不同,S曲线加速度的导数(加加速度Jerk)是连续的。这使得速度变化非常平滑,从根本上消除了刚性冲击,极大地减少了对机械结构的磨损、振动和噪声,对于高速高精设备至关重要。
交叉耦合补偿
核心特点:在精密平台上,一个轴的运动可能会通过机械结构(如龙门架的横梁)对另一个轴产生动态干扰。例如,X轴的启停会导致Y轴的轻微形变或振动。
专业视角:高级的双轴同步控制器会包含交叉耦合补偿算法。它实时监测两个轴的状态,当检测到这种耦合干扰时,会主动向另一个轴输出一个补偿信号,以抵消这种影响,从而保证两个轴作为一个整体协同运动。
集中式规划与分布式执行
核心特点:通常由单一的“主控制器”(Arduino)进行集中式的轨迹规划和同步逻辑运算,然后将生成的位置、速度或转矩指令实时分发给两个轴的BLDC驱动器。
专业视角:这种架构保证了同步逻辑的严格性和一致性。主控制器需要具备足够的算力来实时解算复杂的运动学方程和同步关系,并对两个驱动器的响应一致性有很高要求。
二、 应用场景
该技术广泛应用于需要两个运动轴精确配合以完成复杂任务的自动化设备。
龙门式运动平台
场景描述:这是最典型的应用。X轴和Y轴上的两个BLDC电机必须完美同步,才能保证末端执行器(如激光头、喷印头、抓取器)沿直线或曲线轨迹运动,而不会发生卡死、倾斜或振动。
系统实现:Arduino作为运动控制器,实时计算理想的直线或圆弧插补轨迹,并将分解后的位置指令分别发送给X轴和Y轴的BLDC驱动器。S曲线加速度管理确保了启停和拐角处的平滑过渡。
卷绕/放卷张力控制系统
场景描述:在纺织、印刷、薄膜生产中,放卷轴和收卷轴需要保持严格的线速度同步,同时通过调节力矩来维持中间材料的恒定张力。
系统实现:这是一个速度同步+张力控制的复杂系统。两个BLDC电机分别控制收卷和放卷。Arduino通过测量张力传感器的反馈,实时调整两个电机的转矩指令(可能工作在速度模式或转矩模式),确保在加速、减速和匀速过程中张力恒定。
协同作业机械臂
场景描述:两个简单的、单自由度的机械臂协同搬运一个大型或柔性工件。它们末端的轨迹必须同步,否则会导致工件跌落、倾斜或内部应力。
系统实现:Arduino规划工件质心的运动轨迹,并通过逆向运动学分别计算出两个机械臂关节(BLDC电机)应有的位置/速度指令。加速度管理保证了工件在运动中的稳定性,避免因惯性而滑动或晃动。
高精度3D打印机/CNC
场景描述:实现高质量表面打印和雕刻的关键在于运动平台的平滑和精确同步。
系统实现:采用S曲线加速度规划,可以显著减少打印层表面的振纹(由运动冲击引起),尤其是在模型拐角处。双Z轴BLDC电机的同步控制则保证了喷头平台在垂直方向上的绝对水平。
三、 需要注意的事项(挑战与解决方案)
实现高性能的双轴同步控制,需要克服以下核心挑战:
电机与驱动器性能的一致性
挑战:两个BLDC电机及其驱动器的内阻、KV值、电气时间常数、机械时间常数等微小的差异,会在相同的控制指令下产生不同的动态响应,导致同步误差。
对策:
精细的电机配对:尽可能使用同一批次、型号完全相同的电机和驱动器。
独立PID整定:对每个轴的闭环控制器(位置环、速度环)进行独立的、精细的PID参数整定,使它们的动态响应特性尽可能一致。
反馈系统的精度与实时性
挑战:同步控制严重依赖于高精度的位置反馈(如高分辨率编码器)。如果反馈存在延迟或噪声,同步算法将基于错误的信息进行计算。
对策:
高性能编码器:使用高线数的增量式编码器或绝对值编码器。
高速采样:确保Arduino的程序循环能够以远高于系统带宽的频率读取两个编码器的值,并进行处理。
计算负载与实时性保障
挑战:实时进行轨迹插补、S曲线计算、同步逻辑解算和双路PID控制,对Arduino(尤其是Uno/Nano)的计算能力是巨大考验。计算延迟会直接转化为控制延迟,影响同步精度。
对策:
优化算法:使用查表法、定点数运算等技巧降低计算量。
升级硬件:对于要求高的应用,必须使用更强大的控制器,如Arduino Due、ESP32或专业的STM32系列MCU,它们具有更高的主频和硬件FPU。
机械系统的刚性不足与背隙
挑战:机械连接(如丝杠、皮带、联轴器)存在弹性形变和齿轮背隙。这会导致电机的转动无法精确地传递到负载上,尤其在换向时,会造成同步误差。
对策:
机械设计:尽可能提高机械结构的刚性,并使用消隙机构。
控制策略:采用背隙补偿算法,在电机换向时主动补偿一个微小的过冲。对于刚性不足的问题,可以在控制器中引入振动抑制算法。

1、使用电位器控制两个BLDC电机的同步运动并显示在串口监视器上
// 定义引脚
const int motorPinA1 = 9; // PWM控制引脚A1
const int motorPinA2 = 10; // PWM控制引脚A2
const int motorPinB1 = 6; // PWM控制引脚B1
const int motorPinB2 = 5; // PWM控制引脚B2
const int potPinA = A0; // 电位器A连接的模拟引脚
const int potPinB = A1; // 电位器B连接的模拟引脚
void setup() {
// 初始化串口通信
Serial.begin(9600);
// 设置所有motorPin为输出模式
pinMode(motorPinA1, OUTPUT);
pinMode(motorPinA2, OUTPUT);
pinMode(motorPinB1, OUTPUT);
pinMode(motorPinB2, OUTPUT);
}
void loop() {
// 读取电位器A和B的值
int potValueA = analogRead(potPinA);
int potValueB = analogRead(potPinB);
// 根据电位器值调整电机速度 (映射到0-255)
int speedA = map(potValueA, 0, 1023, 0, 255);
int speedB = map(potValueB, 0, 1023, 0, 255);
// 将PWM信号写入电机引脚
analogWrite(motorPinA1, speedA);
analogWrite(motorPinA2, 0);
analogWrite(motorPinB1, speedB);
analogWrite(motorPinB2, 0);
// 输出当前电位器值和电机速度到串口监视器
Serial.print("Pot A Value: ");
Serial.print(potValueA);
Serial.print("\t Motor A Speed: ");
Serial.print(speedA);
Serial.print("\nPot B Value: ");
Serial.print(potValueB);
Serial.print("\t Motor B Speed: ");
Serial.println(speedB);
// 延迟一段时间
delay(100);
}
要点解读:
硬件连接:两个电位器分别连接到A0和A1引脚,四个BLDC电机的控制线分别连接到第9、10、6和5号数字引脚(支持PWM)。
传感器读取:使用analogRead函数分别读取两个电位器的模拟电压值。
电机速度控制:根据每个电位器的值,通过map函数将其转换为适合PWM的范围(0-255),然后用analogWrite函数分别控制两组电机的速度。
数据显示:利用Serial.print将当前电位器值和各组电机速度输出到串口监视器。
2、使用编码器进行闭环控制并显示在OLED屏幕上
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Encoder.h>
// 定义OLED显示屏相关参数
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// 定义引脚
const int motorPinA1 = 9; // PWM控制引脚A1
const int motorPinA2 = 10; // PWM控制引脚A2
const int motorPinB1 = 6; // PWM控制引脚B1
const int motorPinB2 = 5; // PWM控制引脚B2
Encoder encA(2, 3); // 编码器A接引脚2和3
Encoder encB(4, 7); // 编码器B接引脚4和7
long oldPositionA = 0;
long oldPositionB = 0;
int targetSpeedA = 100; // 目标速度A RPM
int targetSpeedB = 100; // 目标速度B RPM
float kp = 0.5; // 比例增益
void setup() {
// 初始化显示屏
if (!display.begin(SSD1306_I2C_ADDRESS, OLED_RESET)) {
Serial.println(F("SSD1306 allocation failed"));
for (;;);
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
// 设置所有motorPin为输出模式
pinMode(motorPinA1, OUTPUT);
pinMode(motorPinA2, OUTPUT);
pinMode(motorPinB1, OUTPUT);
pinMode(motorPinB2, OUTPUT);
// 初始化串口通信
Serial.begin(9600);
}
void loop() {
long newPositionA = encA.read();
long newPositionB = encB.read();
float errorA = targetSpeedA - (newPositionA - oldPositionA);
float errorB = targetSpeedB - (newPositionB - oldPositionB);
int pwmValueA = constrain(errorA * kp, -255, 255);
int pwmValueB = constrain(errorB * kp, -255, 255);
analogWrite(motorPinA1, abs(pwmValueA));
analogWrite(motorPinA2, pwmValueA < 0 ? 255 : 0);
analogWrite(motorPinB1, abs(pwmValueB));
analogWrite(motorPinB2, pwmValueB < 0 ? 255 : 0);
oldPositionA = newPositionA;
oldPositionB = newPositionB;
// 更新显示屏内容
display.clearDisplay();
display.setCursor(0,0);
display.println("Speed A:");
display.println(newPositionA - oldPositionA);
display.println("Speed B:");
display.println(newPositionB - oldPositionB);
display.display();
// 延迟一段时间
delay(100);
}
要点解读:
硬件连接:两个编码器分别连接到第2、3和4、7号数字引脚,四个BLDC电机的控制线分别连接到第9、10、6和5号数字引脚(支持PWM)。同时,需要连接一个OLED显示屏。
编码器读取:使用Encoder库读取两个编码器的脉冲数,从而计算出每个电机的实际转速。
闭环控制:采用简单的比例控制算法,根据目标速度与实际速度之间的误差来调整PWM信号,从而控制电机速度。
数据展示:在OLED屏幕上实时显示两个电机的实际转速。
3、使用陀螺仪传感器进行姿态控制并管理加速度,显示在TFT液晶屏上
#include <Adafruit_GFX.h>
#include <Adafruit_ST7735.h>
#include <SPI.h>
#include <MPU6050.h>
// 定义TFT显示屏相关参数
#define TFT_CS 10
#define TFT_RST 9
#define TFT_DC 8
Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);
// 定义引脚
const int motorPinA1 = 9; // PWM控制引脚A1
const int motorPinA2 = 10; // PWM控制引脚A2
const int motorPinB1 = 6; // PWM控制引脚B1
const int motorPinB2 = 5; // PWM控制引脚B2
MPU6050 mpu;
float angleA = 0;
float angleB = 0;
int targetAngleA = 0;
int targetAngleB = 0;
float kp = 2.0; // 比例增益
float accLimit = 1.0; // 加速度限制
void setup() {
// 初始化显示屏
tft.initR(INITR_BLACKTAB);
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(1);
// 设置所有motorPin为输出模式
pinMode(motorPinA1, OUTPUT);
pinMode(motorPinA2, OUTPUT);
pinMode(motorPinB1, OUTPUT);
pinMode(motorPinB2, OUTPUT);
// 初始化IMU传感器
Wire.begin();
mpu.initialize();
// 初始化串口通信
Serial.begin(9600);
}
void loop() {
// 获取当前角度
angleA = mpu.getAngleX();
angleB = mpu.getAngleY();
// 计算误差
float errorA = targetAngleA - angleA;
float errorB = targetAngleB - angleB;
// 应用加速度限制
static float prevErrorA = 0;
static float prevErrorB = 0;
float accA = errorA - prevErrorA;
float accB = errorB - prevErrorB;
accA = constrain(accA, -accLimit, accLimit);
accB = constrain(accB, -accLimit, accLimit);
prevErrorA = errorA + accA;
prevErrorB = errorB + accB;
// 计算PWM值
int pwmValueA = constrain((errorA + accA) * kp, -255, 255);
int pwmValueB = constrain((errorB + accB) * kp, -255, 255);
// 根据PWM值调整电机方向与速度
analogWrite(motorPinA1, abs(pwmValueA));
analogWrite(motorPinA2, pwmValueA < 0 ? 255 : 0);
analogWrite(motorPinB1, abs(pwmValueB));
analogWrite(motorPinB2, pwmValueB < 0 ? 255 : 0);
// 更新显示屏内容
tft.fillScreen(ST77XX_BLACK);
tft.setCursor(0, 0);
tft.println("Angle A:");
tft.println(angleA);
tft.println("Angle B:");
tft.println(angleB);
tft.println("Error A:");
tft.println(errorA);
tft.println("Error B:");
tft.println(errorB);
// 延迟一段时间
delay(100);
}
要点解读:
硬件连接:MPU6050陀螺仪传感器通过I2C接口连接到Arduino,四个BLDC电机的控制线分别连接到第9、10、6和5号数字引脚(支持PWM)。同时,需要连接一个TFT液晶显示屏。
姿态检测:使用MPU6050库读取陀螺仪的角度信息。
姿态控制与加速度管理:采用比例控制算法,结合加速度限制策略,根据当前角度与目标角度之间的误差及其变化率来调整PWM信号,从而控制电机以保持特定姿态并平滑加速或减速。
数据展示:在TFT液晶屏上实时显示当前角度、目标角度、误差等信息。

4、双轴机械臂协同控制(位置同步)
#include <SimpleFOC.h>
// 定义两个BLDC电机和驱动器
BLDCMotor motor1 = BLDCMotor(7);
BLDCMotor motor2 = BLDCMotor(8);
BLDCDriver3PWM driver1 = BLDCDriver3PWM(3, 5, 6, 11);
BLDCDriver3PWM driver2 = BLDCDriver3PWM(9, 10, 12, 11);
// 目标位置和当前位置
float targetPos1 = 0, targetPos2 = 0;
float currentPos1 = 0, currentPos2 = 0;
// 加速度限制参数
float maxAccel = 100.0; // 最大加速度(单位:脉冲/秒²)
float lastTime = 0;
float prevSpeed1 = 0, prevSpeed2 = 0;
// PID控制器
PIDController pid1 = {1.0, 0.5, 0.1}; // 电机1 PID参数
PIDController pid2 = {1.0, 0.5, 0.1}; // 电机2 PID参数
void setup() {
Serial.begin(115200);
// 初始化电机1
driver1.init();
motor1.linkDriver(&driver1);
motor1.init();
motor1.enable();
// 初始化电机2
driver2.init();
motor2.linkDriver(&driver2);
motor2.init();
motor2.enable();
lastTime = micros();
}
void loop() {
unsigned long now = micros();
float dt = (now - lastTime) / 1e6; // 计算时间步长(秒)
lastTime = now;
// 目标位置更新(示例:正弦运动)
targetPos1 = sin(millis() / 1000.0) * 100;
targetPos2 = cos(millis() / 1000.0) * 100;
// 加速度限制(梯形速度规划)
float speed1 = (targetPos1 - currentPos1) / dt;
float speed2 = (targetPos2 - currentPos2) / dt;
// 限制加速度
speed1 = constrain(speed1, prevSpeed1 - maxAccel * dt, prevSpeed1 + maxAccel * dt);
speed2 = constrain(speed2, prevSpeed2 - maxAccel * dt, prevSpeed2 + maxAccel * dt);
currentPos1 += speed1 * dt;
currentPos2 += speed2 * dt;
prevSpeed1 = speed1;
prevSpeed2 = speed2;
// PID计算控制量
float error1 = targetPos1 - currentPos1;
float error2 = targetPos2 - currentPos2;
float control1 = pid1.calculate(error1, 0);
float control2 = pid2.calculate(error2, 0);
// 控制电机
motor1.speed(control1);
motor2.speed(control2);
// 串口显示
Serial.print("电机1目标: ");
Serial.print(targetPos1);
Serial.print(" | 当前: ");
Serial.print(currentPos1);
Serial.print(" | 控制量: ");
Serial.print(control1);
Serial.print(" | 电机2目标: ");
Serial.print(targetPos2);
Serial.print(" | 当前: ");
Serial.print(currentPos2);
Serial.print(" | 控制量: ");
Serial.println(control2);
delay(10); // 控制周期
}
要点解读
加速度限制:
通过constrain限制速度变化率,避免瞬时加速度过大。
使用prevSpeed记录上一周期速度,确保加速度连续。
同步控制:
两轴独立PID控制,但共享时间步长dt,保证协同性。
应用场景:
适用于机械臂、3D打印机等需要多轴位置同步的场景。
5、差速转向车的加速度管理
#include <SimpleFOC.h>
// 定义左右BLDC电机和驱动器
BLDCMotor motorLeft = BLDCMotor(7);
BLDCMotor motorRight = BLDCMotor(8);
BLDCDriver3PWM driverLeft = BLDCDriver3PWM(3, 5, 6, 11);
BLDCDriver3PWM driverRight = BLDCDriver3PWM(9, 10, 12, 11);
// 目标速度和当前速度
float targetSpeedLeft = 0, targetSpeedRight = 0;
float currentSpeedLeft = 0, currentSpeedRight = 0;
// 加速度限制
float maxAccel = 50.0; // 最大加速度(单位:RPM/秒²)
float lastTime = 0;
// PID控制器
PIDController pidLeft = {0.8, 0.1, 0.05};
PIDController pidRight = {0.8, 0.1, 0.05};
void setup() {
Serial.begin(115200);
// 初始化电机
driverLeft.init();
motorLeft.linkDriver(&driverLeft);
motorLeft.init();
motorLeft.enable();
driverRight.init();
motorRight.linkDriver(&driverRight);
motorRight.init();
motorRight.enable();
lastTime = micros();
}
void loop() {
unsigned long now = micros();
float dt = (now - lastTime) / 1e6;
lastTime = now;
// 目标速度更新(示例:键盘控制或预设路径)
targetSpeedLeft = 100; // 左电机目标速度(RPM)
targetSpeedRight = 80; // 右电机目标速度(差速转向)
// 加速度限制
float accelLeft = (targetSpeedLeft - currentSpeedLeft) / dt;
float accelRight = (targetSpeedRight - currentSpeedRight) / dt;
accelLeft = constrain(accelLeft, -maxAccel, maxAccel);
accelRight = constrain(accelRight, -maxAccel, maxAccel);
currentSpeedLeft += accelLeft * dt;
currentSpeedRight += accelRight * dt;
// PID计算控制量
float errorLeft = targetSpeedLeft - currentSpeedLeft;
float errorRight = targetSpeedRight - currentSpeedRight;
float controlLeft = pidLeft.calculate(errorLeft, 0);
float controlRight = pidRight.calculate(errorRight, 0);
// 控制电机
motorLeft.speed(controlLeft);
motorRight.speed(controlRight);
// 串口显示
Serial.print("左电机目标: ");
Serial.print(targetSpeedLeft);
Serial.print(" | 当前: ");
Serial.print(currentSpeedLeft);
Serial.print(" | 控制量: ");
Serial.print(controlLeft);
Serial.print(" | 右电机目标: ");
Serial.print(targetSpeedRight);
Serial.print(" | 当前: ");
Serial.print(currentSpeedRight);
Serial.print(" | 控制量: ");
Serial.println(controlRight);
delay(10); // 控制周期
}
要点解读
差速转向逻辑:
左右电机速度差实现转向(如targetSpeedLeft > targetSpeedRight时左转)。
加速度管理:
通过限制加速度避免急加速/急减速导致的打滑或机械冲击。
应用场景:
智能车、AGV等需要平滑运动控制的场景。
6、电梯门双电机同步控制(位置+加速度)
#include <SimpleFOC.h>
// 定义两个BLDC电机和驱动器
BLDCMotor motor1 = BLDCMotor(7);
BLDCMotor motor2 = BLDCMotor(8);
BLDCDriver3PWM driver1 = BLDCDriver3PWM(3, 5, 6, 11);
BLDCDriver3PWM driver2 = BLDCDriver3PWM(9, 10, 12, 11);
// 目标位置和当前位置
float targetPos = 0; // 统一目标位置(两电机同步)
float currentPos1 = 0, currentPos2 = 0;
// 加速度限制
float maxAccel = 80.0; // 最大加速度(单位:脉冲/秒²)
float lastTime = 0;
float prevSpeed1 = 0, prevSpeed2 = 0;
// PID控制器
PIDController pid1 = {1.2, 0.3, 0.1};
PIDController pid2 = {1.2, 0.3, 0.1};
void setup() {
Serial.begin(115200);
// 初始化电机
driver1.init();
motor1.linkDriver(&driver1);
motor1.init();
motor1.enable();
driver2.init();
motor2.linkDriver(&driver2);
motor2.init();
motor2.enable();
lastTime = micros();
}
void loop() {
unsigned long now = micros();
float dt = (now - lastTime) / 1e6;
lastTime = now;
// 目标位置更新(示例:按钮触发)
targetPos = (millis() / 2000) % 2 == 0 ? 0 : 1000; // 来回运动
// 加速度限制(两电机同步规划)
float speed1 = (targetPos - currentPos1) / dt;
float speed2 = (targetPos - currentPos2) / dt;
speed1 = constrain(speed1, prevSpeed1 - maxAccel * dt, prevSpeed1 + maxAccel * dt);
speed2 = constrain(speed2, prevSpeed2 - maxAccel * dt, prevSpeed2 + maxAccel * dt);
currentPos1 += speed1 * dt;
currentPos2 += speed2 * dt;
prevSpeed1 = speed1;
prevSpeed2 = speed2;
// PID计算控制量
float error1 = targetPos - currentPos1;
float error2 = targetPos - currentPos2;
float control1 = pid1.calculate(error1, 0);
float control2 = pid2.calculate(error2, 0);
// 控制电机
motor1.speed(control1);
motor2.speed(control2);
// 串口显示
Serial.print("目标位置: ");
Serial.print(targetPos);
Serial.print(" | 电机1当前: ");
Serial.print(currentPos1);
Serial.print(" | 控制量: ");
Serial.print(control1);
Serial.print(" | 电机2当前: ");
Serial.print(currentPos2);
Serial.print(" | 控制量: ");
Serial.println(control2);
delay(10); // 控制周期
}
要点解读
同步控制:
两电机共享同一目标位置targetPos,但独立PID控制以补偿机械差异。
加速度管理:
梯形速度规划确保电梯门启停平滑,避免振动。
安全机制:
可添加位置传感器(如编码器)反馈,实现闭环控制。
应用场景:
电梯门、舞台幕布等需要高精度同步的场景。
注意,以上案例只是为了拓展思路,仅供参考。它们可能有错误、不适用或者无法编译。您的硬件平台、使用场景和Arduino版本可能影响使用方法的选择。实际编程时,您要根据自己的硬件配置、使用场景和具体需求进行调整,并多次实际测试。您还要正确连接硬件,了解所用传感器和设备的规范和特性。涉及硬件操作的代码,您要在使用前确认引脚和电平等参数的正确性和安全性。

793

被折叠的 条评论
为什么被折叠?



