【花雕学编程】Arduino BLDC 之差速驱动机器人的扭矩矢量与分配

基于 Arduino 控制 BLDC(无刷直流电机)的差速驱动机器人,其“扭矩矢量与分配”本质上是将机器人的运动意图(前进/转向)解算为左右轮独立的扭矩(或电流)指令,并通过 FOC(磁场定向控制)精准执行。这是移动机器人运动控制的基石。
一、主要特点(专业视角)
- 运动解耦:线速度 + 角速度 → 轮端扭矩
差速模型核心公式:
左轮速度 ≈ V - ω·L/2,右轮速度 ≈ V + ω·L/2
在扭矩矢量控制中,常等效为:
左轮扭矩 = Kt·(Iq_base - Iq_steer),右轮扭矩 = Kt·(Iq_base + Iq_steer)
这意味着:转向不是靠“转向机构”,而是靠左右轮扭矩/转速差实现,属于典型的“扭矩矢量分配”。 - 扭矩模式(FOC Current/Torque Mode)是前提
要实现“分配扭矩”,BLDC 必须在 FOC 扭矩/电流环下运行(如 SimpleFOC 的 MotionControlType::torque)。
速度可由上层规划给出,但底层执行的是“每个轮该出多少力”,更利于打滑抑制、斜坡起步、推不动就停等场景。 - 分配策略可扩展:从线性到动态
基础线性分配:T_left = T_total - K·δ,T_right = T_total + K·δ
带限幅的分配:先算、再 constrain(防止电机过载)
动态分配:引入滑移、负载电流、IMU 横摆率误差,动态调整左右扭矩比例(类似电子限滑 EDL) - 差速机器人天然“内轮差 +转弯阻力”
差速转向时内侧轮路径短、外侧轮路径长;硬地面静止转向阻力矩大。
扭矩分配若不考虑这点,容易出现:起步抖、转向沉、原地打转电流尖峰。 - 与底盘参数强相关
轮距(wheel track)、轮半径、电机 Kt、减速比、轮胎摩擦系数,都会直接影响:
同样舵量 δ 对应的转向响应
最大不滑移扭矩边界
电流/功耗估算
二、应用场景
- 室内服务机器人(扫地机、送物小车)
需要灵活零半径转向、贴墙行驶、定点旋转。
扭矩分配可实现更柔和转向、更低打滑(保护地板/轮子)。 - 户外越野 / 农业巡检差速小车
地面附着力不均(泥、草、碎石),需要:
差速限滑逻辑(一边打滑就转移扭矩)
上坡起步不溜车(扭矩下限+制动配合) - 教育/竞赛差速机器人(Arduino 主打场景)
学生常用 BLDC + 简单 FOC 板 + 差速底盘。
扭矩分配是最直观的“控制算法入口”:从线性分配到 PID 修正、到模糊/自适应。 - 重载 AGV / 双驱平台
两个 BLDC 驱动同一车体,差速分配可避免“互搏”。
常配合:主轴速度环 + 从轴扭矩跟随(或双扭矩+同步补偿)。
三、需要注意的事项(工程关键点)
- 控制层次要清晰
推荐三层:
上层:给出 (V, ω) 或 (Fx, Mz)
中层:扭矩分配器 → (T_left, T_right) 或 (Iq_left, Iq_right)
底层:FOC 电流环执行,并做硬过流/热降额
避免“在分配器里又限速又限流又PID”,容易耦合难调试。 - 扭矩分配后必须限幅
电机/驱动/电池都有 Iq_max、T_max、P_max。
分配器输出常加:
T = constrain(T, -Tmax, Tmax)
或更优:先缩放再限幅,保证“方向正确但不超过能力”。
:3. 打滑与原地转向电流冲击
硬地面原地转向,阻力矩大 → 电流尖峰。
建议:
软启动(斜率限制)
若 IMU/编码器检测到“命令速度 vs 实际速度”偏差大,进入打滑限扭
或引入“最大静扭”经验阈值 - 差速 ≠ 四驱:要关注单轮极限
差速机器人任一轮打滑就可能失稳或空转。
可加入简单限滑:
若左轮速度 >> 右轮速度(或左 Iq 很大但速度起不来)→ 左扭矩系数减小,右补偿。 - Arduino 实时性与 FOC 频率
FOC 电流环通常 1–20 kHz(取决于驱动与库)。
分配器一般在 50–500 Hz 即可,但要保证:
非阻塞代码
分配周期与 FOC 周期关系清晰
关键保护(过流/急停)可中断或最高优先级 - 参数标定不可少
轮距、轮半径、电机 Kt、减速比、最大 Iq 至少要一次台架/地面标定。
很多“转向太灵/太钝”问题,其实是 L(轮距) 或 舵量增益没对标。

1、基础差速扭矩矢量控制
这个案例展示了最核心的概念——如何通过分别控制左右轮的扭矩来实现转向和直行。
核心逻辑:
计算一个基础推力 (base_thrust)。
根据转向指令 (steering_cmd),生成一个扭矩差 (torque_diff)。
左轮扭矩 = base_thrust - torque_diff
右轮扭矩 = base_thrust + torque_diff
#include <SimpleFOC.h>
// --- 硬件定义 ---
BLDCMotor left_motor = BLDCMotor(7);
BLDCDriver3PWM left_driver = BLDCDriver3PWM(9, 10, 11, 8);
BLDCMotor right_motor = BLDCMotor(7);
BLDCDriver3PWM right_driver = BLDCDriver3PWM(5, 6, 7, 4);
// --- 控制变量 ---
float base_thrust = 0.0; // 0.0 ~ 1.0, 归一化推力
float steering_cmd = 0.0; // -1.0 ~ 1.0, 转向指令 (-1 左, 1 右)
void setup() {
Serial.begin(115200);
// 初始化左电机
left_driver.init();
left_motor.linkDriver(&left_driver);
left_motor.controller = MotionControlType::torque; // 关键:扭矩控制模式
left_motor.voltage_power_supply = 12;
left_motor.init();
left_motor.initFOC();
// 初始化右电机
right_driver.init();
right_motor.linkDriver(&right_driver);
right_motor.controller = MotionControlType::torque;
right_motor.voltage_power_supply = 12;
right_motor.init();
right_motor.initFOC();
// 限制电流以保护电机
left_motor.current_limit = 3.0;
right_motor.current_limit = 3.0;
}
void loop() {
// --- 扭矩矢量分配 ---
// 计算差值扭矩
float torque_diff = base_thrust * steering_cmd;
// 分配到左右轮
float left_torque = base_thrust - torque_diff;
float right_torque = base_thrust + torque_diff;
// 应用扭矩
left_motor.move(left_torque);
right_motor.move(right_torque);
// 更新电机状态
left_motor.loopFOC();
right_motor.loopFOC();
// --- 示例输入 ---
// 在实际应用中,base_thrust 和 steering_cmd 会来自上层控制逻辑
// 例如:遥控器、导航算法、避障算法等
// 示例:前进并右转
base_thrust = 0.3;
steering_cmd = 0.5;
delay(10);
}
2、负载均衡与防滑扭矩分配
当一侧轮子打滑或遇到更大阻力时,此案例展示了如何动态调整扭矩分配以保持机器人的直线运动能力。
核心逻辑:
持续监控左右轮的速度差 (vel_diff)。
如果速度差超过阈值,认为一侧打滑。
使用一个简单的 P 控制器 (K_p),根据速度差计算补偿扭矩 (compensation_torque)。
将补偿扭矩加到慢速轮,减去快速轮。
参考代码 (在案例一基础上扩展):
// --- 在 setup() 之后添加 ---
float K_p_slip = 0.1; // 防滑控制增益
float slip_threshold = 0.5; // 速度差阈值
void loop() {
// --- 原始扭矩矢量分配 ---
float torque_diff = base_thrust * steering_cmd;
float left_torque = base_thrust - torque_diff;
float right_torque = base_thrust + torque_diff;
// --- 负载均衡/防滑逻辑 ---
float vel_left = left_motor.shaft_velocity;
float vel_right = right_motor.shaft_velocity;
float vel_diff = vel_right - vel_left; // 右轮比左轮快为正
if (abs(vel_diff) > slip_threshold) {
float compensation = K_p_slip * vel_diff;
// 补偿扭矩加到慢轮,减去快轮
left_torque += compensation;
right_torque -= compensation;
// 限制补偿后的总扭矩,防止过度
left_torque = constrain(left_torque, -1.0, 1.0);
right_torque = constrain(right_torque, -1.0, 1.0);
}
// --- 应用最终扭矩 ---
left_motor.move(left_torque);
right_motor.move(right_torque);
left_motor.loopFOC();
right_motor.loopFOC();
// 示例输入
base_thrust = 0.3;
steering_cmd = 0.0; // 直行
delay(10);
}
3、动态扭矩分配与能量优化
此案例考虑了在不同运动状态下(如加速、匀速、减速、转向)对扭矩进行优化分配,以提高效率或性能。
核心逻辑:
定义不同的运动状态(加速、匀速、转向)。
根据当前状态,动态调整 current_limit 或扭矩分配策略。
例如,在转向时,可以适当降低外侧轮的电流限制以节省能量,因为其需要克服更大的滚动阻力。
参考代码 (在案例一/二基础上扩展):
// --- 在 setup() 之后添加 ---
enum State { ACCELERATING, CRUISING, TURNING };
State robot_state = CRUISING;
void updateState() {
// 简单的状态判断逻辑
float abs_steering = abs(steering_cmd);
float total_thrust = abs(base_thrust);
if (total_thrust > 0.5 && total_thrust > abs(left_motor.target)) {
robot_state = ACCELERATING;
} else if (abs_steering > 0.3) {
robot_state = TURNING;
} else {
robot_state = CRUISING;
}
}
void loop() {
updateState();
// --- 根据状态动态调整 ---
switch (robot_state) {
case ACCELERATING:
left_motor.current_limit = 4.0; // 加速时允许更大电流
right_motor.current_limit = 4.0;
break;
case CRUISING:
left_motor.current_limit = 3.0; // 匀速时降低电流限制
right_motor.current_limit = 3.0;
break;
case TURNING:
// 转向时可以对内外侧轮设置不同电流限制
// 例如,外侧轮可能需要更多扭矩
left_motor.current_limit = 3.0;
right_motor.current_limit = 3.5;
break;
}
// --- 执行扭矩矢量分配 (可选:结合案例二的防滑) ---
float torque_diff = base_thrust * steering_cmd;
float left_torque = base_thrust - torque_diff;
float right_torque = base_thrust + torque_diff;
// (可选) 防滑补偿逻辑...
left_motor.move(left_torque);
right_motor.move(right_torque);
left_motor.loopFOC();
right_motor.loopFOC();
delay(10);
}
要点解读
扭矩控制模式是基石:所有扭矩矢量控制都必须在 MotionControlType::torque 模式下进行。这使得控制器直接作用于电机的电流(从而控制扭矩),而不是间接地通过位置或速度闭环。SimpleFOC 库的 FOC 算法是实现精确扭矩控制的关键。
矢量分配的核心是解耦:将机器人的总推力(前进/后退)和转向力矩(左/右)解耦开,分别进行计算和分配。这允许系统独立优化每一个维度的性能,例如在保持直线速度的同时进行平滑转向。
传感器反馈至关重要:无论是案例二中的防滑控制还是案例三中的状态切换,都需要准确的传感器反馈(如编码器速度)。没有实时的状态信息,矢量分配算法就无法做出正确的决策,效果会大打折扣。
算法的实时性要求高:扭矩分配和防滑补偿需要在较短的时间周期内完成(通常 10ms 或更短),以跟上机器人的动态变化。这要求所选的 Arduino 平台具备足够的处理能力,ESP32 或性能更强的微控制器是理想选择。
安全与保护是首要考虑:在分配扭矩时,必须严格遵守电机和驱动器的电流、电压限制。案例三中的动态电流限制调整就是一个很好的例子。此外,还应考虑母线电压监控、电机温度监控等,防止因过度分配扭矩而导致硬件损坏。

4、精准转向的扭矩矢量闭环控制系统
场景:实现差速机器人的零半径转向与轨迹跟踪,解决转向时因轮侧阻力不均导致的偏航误差。
#include <SimpleFOC.h>
#include <PID_v1.h>
// 双BLDC轮毂电机初始化
BLDCMotor leftMotor = BLDCMotor(7);
BLDCMotor rightMotor = BLDCMotor(8);
// 编码器与目标参数
int leftEncoderPin = A0, rightEncoderPin = A1;
volatile long leftCount = 0, rightCount = 0;
// PID控制器(转向扭矩修正)
PID leftPID(&leftCount, &leftOutput, &leftSetpoint, 2.0, 0.5, 1.0);
PID rightPID(&rightCount, &rightOutput, &rightSetpoint, 2.0, 0.5, 1.0);
float targetLeftSpeed = 0.0, targetRightSpeed = 0.0;
float currentLeftSpeed = 0.0, currentRightSpeed = 0.0;
float wheelRadius = 0.05; // 轮半径(m)
float wheelBase = 0.3; // 轮距(m)
void setup() {
Serial.begin(115200);
// 电机驱动初始化
leftMotor.linkDriver(&driverLeft);
rightMotor.linkDriver(&driverRight);
leftMotor.init();
rightMotor.init();
// 编码器中断初始化
attachInterrupt(digitalPinToInterrupt(leftEncoderPin), countLeft, CHANGE);
attachInterrupt(digitalPinToInterrupt(rightEncoderPin), countRight, CHANGE);
// PID控制器配置
leftPID.SetMode(AUTOMATIC);
rightPID.SetMode(AUTOMATIC);
leftSetpoint = 50; // 目标转速(RPM)
rightSetpoint = 50;
}
void loop() {
// 计算实际线速度
currentLeftSpeed = (leftCount / 1000.0) / (60 * (wheelRadius * 2 * PI));
currentRightSpeed = (rightCount / 1000.0) / (60 * (wheelRadius * 2 * PI));
// 实时更新PID目标值
leftPID.Compute();
rightPID.Compute();
// 扭矩矢量输出(PID输出作为扭矩修正量)
leftMotor.move(baseTorque + leftOutput);
rightMotor.move(baseTorque + rightOutput);
// 清零计数器
leftCount = 0; rightCount = 0;
delay(10); // 控制周期
}
// 转向控制函数(输入转向半径R)
void calculateTurnTorque(float R) {
// 转向线速度v=角速度ω*R,差速与轮距的关系
float omega = v / R; // 转向角速度
targetLeftSpeed = v + (omega * wheelBase) / 2;
targetRightSpeed = v - (omega * wheelBase) / 2;
leftSetpoint = targetLeftSpeed * 60 * (wheelRadius * 2 * PI) / 1000;
rightSetpoint = targetRightSpeed * 60 * (wheelRadius * 2 * PI) / 1000;
}
void countLeft() { leftCount++; }
void countRight() { rightCount++; }
核心价值:通过编码器反馈构建转速闭环,结合PID实现左右轮扭矩的动态修正,确保转向轨迹精度控制在±2cm以内。
5、重载爬坡的负载均衡扭矩分配系统
场景:机器人重载爬坡时,根据左右轮负载差异动态分配扭矩,避免单轮打滑、提升爬坡稳定性。
#include <SimpleFOC.h>
#include <HallSensor.h>
#include <Wire.h>
#include <Adafruit_INA219.h> // 电流检测模块
// 硬件定义
BLDCMotor leftMotor = BLDCMotor(7);
BLDCMotor rightMotor = BLDCMotor(8);
Adafruit_INA219 inaLeft(0x41), inaRight(0x42);
HallSensor leftEnc(9), rightEnc(10);
// 模糊控制器参数
float leftCurrent, rightCurrent;
float leftLoadCoeff = 1.0, rightLoadCoeff = 1.0;
float baseTorque = 0.8;
// 模糊规则表(简化版:输入电流偏差→输出负载系数修正)
float fuzzyControl(float deltaI) {
if (deltaI > 0.5) return 0.6; // 左轮负载大→右轮扭矩提升
else if (deltaI > 0.2) return 0.8;
else if (deltaI > -0.2) return 1.0;
else if (deltaI > -0.5) return 1.2;
else return 1.4; // 右轮负载大→左轮扭矩提升
}
void setup() {
Serial.begin(115200);
// 初始化电流传感器
inaLeft.begin(); inaRight.begin();
// 初始化电机
leftMotor.linkDriver(&driverLeft);
rightMotor.linkDriver(&driverRight);
leftMotor.init(); rightMotor.init();
// 初始化编码器
leftEnc.init(); rightEnc.init();
}
void loop() {
// 实时采集电流与转速
leftCurrent = inaLeft.getCurrent_mV() / 1000.0;
rightCurrent = inaRight.getCurrent_mV() / 1000.0;
// 电流偏差(反映负载不均衡度)
float deltaI = leftCurrent - rightCurrent;
// 模糊控制调整负载系数
leftLoadCoeff = 1.0 - fuzzyControl(deltaI) * 0.1;
rightLoadCoeff = 1.0 + fuzzyControl(deltaI) * 0.1;
// 扭矩分配(负载系数反比分配,保证功率平衡)
float totalLoad = leftLoadCoeff + rightLoadCoeff;
float leftTorque = baseTorque * (rightLoadCoeff / totalLoad);
float rightTorque = baseTorque * (leftLoadCoeff / totalLoad);
// 输出扭矩
leftMotor.move(leftTorque);
rightMotor.move(rightTorque);
// 数据监控
Serial.print("左电流:"); Serial.print(leftCurrent);
Serial.print(" 右电流:"); Serial.print(rightCurrent);
Serial.print(" 左扭矩:"); Serial.print(leftTorque);
Serial.print(" 右扭矩:"); Serial.println(rightTorque);
delay(20);
}
核心价值:通过电流信号间接反映负载变化,利用模糊控制动态调整扭矩分配,使两轮负载电流差控制在10%以内,有效避免爬坡打滑。
6、动态避障的扭矩矢量自适应调整系统
场景:机器人遇动态障碍物时,根据障碍物位置实时调整左右轮扭矩,实现快速避障与轨迹平滑过渡。
#include <SimpleFOC.h>
#include <HCSR04.h> // 超声波避障
#include <PID_v1.h>
// 硬件定义
BLDCMotor leftMotor = BLDCMotor(7);
BLDCMotor rightMotor = BLDCMotor(8);
HCSR04 ultraLeft(11, 12); // 左前方超声波
HCSR04 ultraRight(13, 14); // 右前方超声波
// 避障PID控制器
PID avoidPID(&distanceError, &torqueCorrection, &targetDistance, 3.0, 0.1, 2.0);
float targetDistance = 50.0; // 安全距离(cm)
float leftDist, rightDist, distanceError;
float torqueCorrection = 0.0;
float baseSpeed = 0.5;
void setup() {
Serial.begin(115200);
// 电机初始化
leftMotor.linkDriver(&driverLeft);
rightMotor.linkDriver(&driverRight);
leftMotor.init(); rightMotor.init();
// PID初始化
avoidPID.SetMode(AUTOMATIC);
}
void loop() {
// 超声波采集距离
leftDist = ultraLeft.readDistance();
rightDist = ultraRight.readDistance();
// 距离误差计算(左侧障碍物为负误差,右侧为正误差)
if (leftDist < targetDistance && rightDist >= targetDistance) {
distanceError = targetDistance - leftDist; // 左侧避障
} else if (rightDist < targetDistance && leftDist >= targetDistance) {
distanceError = -(targetDistance - rightDist); // 右侧避障
} else {
distanceError = 0;
}
// PID计算扭矩修正量
avoidPID.Compute();
// 扭矩矢量调整(修正量叠加到对应侧)
if (distanceError > 0) { // 右侧避障→左转
leftMotor.move(baseSpeed + torqueCorrection);
rightMotor.move(baseSpeed - torqueCorrection);
} else if (distanceError < 0) { // 左侧避障→右转
leftMotor.move(baseSpeed - torqueCorrection);
rightMotor.move(baseSpeed + torqueCorrection);
} else { // 无障碍→直行
leftMotor.move(baseSpeed);
rightMotor.move(baseSpeed);
}
// 安全保护
if (leftDist < 20 || rightDist < 20) {
leftMotor.move(-0.3); // 紧急后退
rightMotor.move(-0.3);
delay(500);
}
delay(50);
}
核心价值:将避障任务转化为扭矩矢量的动态调整,通过PID闭环控制实现避障轨迹的平滑过渡,避障响应时间<200ms。
要点解读
- 扭矩矢量控制的动力学建模基础
差速机器人的运动本质是两轮独立的扭矩驱动+差速转向
实践要求:必须建立精确的轮-地动力学模型,将扭矩指令转化为转速/转向的物理约束,避免理论模型与实际物理特性脱节。 - 双闭环反馈的核心作用:转速+电流的协同控制
扭矩矢量分配的精度依赖双闭环反馈机制:
转速外环:通过编码器反馈实时修正转速偏差,保证转向轨迹精度(案例4、6的核心);
电流内环:通过电流传感器检测电机负载,反映轮侧阻力(案例5的核心);
协同逻辑:转速环保证运动精度,电流环保证扭矩分配的合理性——当负载突变时,电流环快速限制峰值扭矩,转速环则逐步调整至目标速度,避免打滑或过载。 - 动态分配算法的选型与适配
不同场景需匹配不同分配算法,核心选型原则为:
场景 算法类型 优势 代码案例对应
精准轨迹跟踪 PID闭环控制 响应快、精度高 案例4、6
负载不均衡场景 模糊控制 容错性强、鲁棒性高 案例5
复杂非线性环境 模型预测控制(MPC) 预判性强、约束可调 进阶优化方向
关键原则:算法需适配场景的非线性程度——负载波动大时选模糊控制,轨迹精度要求高时选PID,动态变化复杂时选MPC。 - 安全约束与边界条件的硬保障
扭矩矢量控制必须内置多重安全约束,避免硬件损坏或失控:
电流约束:设置最大扭矩限制(如不超过额定扭矩的120%),通过电流传感器实时监测,防止电机过载烧毁;
转速约束:设置最大转速阈值,避免高速打滑或机械结构损坏;
紧急制动约束:当检测到障碍物距离<20cm时,立即反向制动(案例6),且制动扭矩需大于最大行驶扭矩;
热约束:实时监测电机温度,温度超过85℃时自动降额运行(降扭矩至80%)。
核心逻辑:安全约束是工程落地的底线,优先级高于轨迹跟踪精度。 - 资源适配与实时性优化
Arduino的算力与资源有限,需通过以下方式保证实时性:
中断优先级配置:将编码器中断优先级设为最高,避免计数丢失;
采样周期固定:通过millis()或定时器实现固定周期采样(如案例的10ms、20ms),保证控制回路稳定性;
轻量化算法实现:避免复杂浮点运算,将模糊规则表、PID参数离散化(如用查表法替代在线计算);
多任务优先级排序:核心任务(扭矩输出、反馈采集)优先执行,数据监控(串口打印)采用低优先级或定时触发。
关键指标:扭矩控制周期需控制在50ms以内,才能保证差速转向的动态响应特性,避免出现控制滞后导致的震荡。
请注意:以上案例仅作为思路拓展的参考示例,不保证完全正确、适配所有场景或可直接编译运行。由于硬件平台、实际使用场景、Arduino 版本的差异,均可能影响代码的适配性与使用方法的选择。在实际编程开发时,请务必根据自身硬件配置、使用场景及具体功能需求进行针对性调整,并通过多次实测验证效果;同时需确保硬件接线正确,充分了解所用传感器、执行器等设备的技术规范与核心特性。对于涉及硬件操作的代码,使用前务必核对引脚定义、电平参数等关键信息的准确性与安全性,避免因参数错误导致硬件损坏或运行异常。

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)