Arduino 6.5 寸轮毂电机智能跟随机器人底盘设计与实现
基于 Arduino 与 6.5 寸轮毂电机的智能动态跟随机器人底盘,是一种将高扭矩动力单元与实时感知决策系统深度融合的移动平台方案。利用轮毂电机'轮内驱动'的紧凑特性,结合主控板的灵活控制能力,旨在实现对人或特定目标的平滑、抗扰、低延迟伴随运动。
核心架构与特点
一体化高扭矩动力架构
直驱/准直驱结构让 6.5 寸轮毂电机将 BLDC 电机、行星减速器(常见速比 1:101:30)、轮毂及轴承高度集成。省去了皮带、链条等中间传动环节,传动效率高(>85%),结构紧凑,底盘离地间隙低,重心稳。
得益于内置减速,轮毂电机在低转速下可输出极大扭矩(峰值可达 825 N·m),能轻松驱动 30~80kg 级底盘,具备良好的爬坡和越障能力,且低速运行平稳无顿挫。电机自带霍尔反馈,可直接用于测速和转向判断,无需外接编码器即可实现速度闭环控制,为里程计提供基础数据。
分层式智能控制策略
上层负责轨迹规划:根据感知到的目标相对位姿(距离、方位角、速度),规划出期望的底盘线速度与角速度。 底层采用差速 PID 闭环:Arduino 主控接收上层指令,通过双路 PID 控制器分别调节左右轮毂电机的转速,利用差速运动学实现前进、后退、原地旋转及任意半径转向,响应速度快,机动性强。
关键挑战与注意事项
电源管理与电磁兼容(EMC)
轮毂电机启动电流极大(峰值可达 10A 以上),严禁使用同一路电源直接为 Arduino 及传感器供电,否则电压跌落将导致 MCU 复位。必须采用隔离 DC-DC 模块(如 24V 转 5V)为控制电路单独供电。 在 ESC(电调)电源输入端并联大容量低 ESR 电解电容(1000μF~4700μF),吸收电机换向产生的反电动势尖峰,稳定母线电压。动力线(粗)与信号线(细)必须分开走线,避免平行布线,最好垂直交叉。霍尔线、IMU 线需使用屏蔽线,防止 PWM 噪声干扰传感器读数。
控制算法的实时性与平滑性
标准 Arduino Uno(ATmega328P)处理复杂的传感器融合(如卡尔曼滤波)和多路 PID 闭环时可能力不从心。推荐使用 ESP32(双核,可一核处理通信一核处理控制)或 Teensy 4.0 等高算力板卡,确保控制频率≥50Hz。 直接给阶跃速度指令会导致电机冲击大、轮胎打滑。必须采用 S 型速度规划,限制加加速度(Jerk),使速度曲线平滑过渡,提升乘坐舒适性和跟随精度。在目标突然消失或被障碍物阻挡时,PID 积分项会累积导致电机'飞车'。必须设置积分限幅和失控保护逻辑(如信号丢失超时自动刹车)。
机械安装与安全冗余
6.5 寸轮毂电机通常通过 16mm 轴或法兰固定。必须使用紧定螺钉 + 夹紧套或刚性连接板确保轴不松动,任何晃动都会导致霍尔测速不准和底盘跑偏。PU 实心胎适合室内平坦地面,控制精准;橡胶充气胎适合室外不平地面,减震好、越障强。 硬件急停必须设计独立的回路(如串联急停按钮),当触发时直接切断电机供电,优先级高于软件逻辑。代码中限制 PWM 输出最大值,防止因算法 bug 输出全速指令;同时设置软件限位,防止机器人冲出安全区域。
多场景跟随方案实战
1. UWB 超宽带定位差速跟随
通过 UWB 模块(如 DW1000)获取目标与机器人的相对位置,使用 PID 算法控制轮毂电机实现平滑跟随。这里需要用到 SimpleFOC Shield 驱动电机,配合 Arduino Mega/Due 的多串口能力。
#include<SimpleFOC.h>
#include<DW1000.h>
// 左轮电机配置
BLDCMotor leftMotor(7);
BLDCDriver3PWM leftDriver(9,10,11,8);
MagneticSensorI2C leftEncoder(AS5600_I2C);
// 右轮电机配置
BLDCMotor rightMotor(12);
BLDCDriver3PWM rightDriver(13,14,15,16);
MagneticSensorI2C rightEncoder(AS5600_I2C);
// 状态变量
float targetX = 0, targetY = 0;
float robotX = 0, robotY = 0;
float desiredDistance = 1.0;
float desiredAngle = 0;
// PID 参数
float Kp_dist = 0.8, Ki_dist = 0.05, Kd_dist = 0.1;
float Kp_angle = 1.0, Ki_angle = 0.1, Kd_angle = 0.2;
float lastErrorDist = 0;
float lastErrorAngle = 0;
void setup() {
// 电机初始化
leftMotor.linkSensor(&leftEncoder);
leftMotor.linkDriver(&leftDriver);
leftMotor.controller = MotionControlType::velocity;
leftMotor.PID_velocity.P = 0.2;
leftMotor.initFOC();
rightMotor.linkSensor(&rightEncoder);
rightMotor.linkDriver(&rightDriver);
rightMotor.controller = MotionControlType::velocity;
rightMotor.PID_velocity.P = 0.2;
rightMotor.initFOC();
// UWB 初始化
DW1000.begin(Serial1);
DW1000.setAddress(0x1234);
Serial.begin(115200);
}
void loop() {
// 获取目标位置
if (DW1000.available()) {
float dist, angle;
DW1000.getRelativePosition(&dist, &angle);
targetX = robotX + dist * cos(angle);
targetY = robotY + dist * sin(angle);
}
// 计算误差
float dx = targetX - robotX;
float dy = targetY - robotY;
float currentDistance = sqrt(dx * dx + dy * dy);
float currentAngle = atan2(dy, dx);
float errorDist = desiredDistance - currentDistance;
float errorAngle = desiredAngle - currentAngle;
errorAngle = (errorAngle > PI) ? errorAngle - 2 * PI : (errorAngle < -PI) ? errorAngle + 2 * PI : errorAngle;
// PID 计算
static float integralDist = 0, integralAngle = 0;
float derivativeDist = (errorDist - lastErrorDist) / 0.02;
float derivativeAngle = (errorAngle - lastErrorAngle) / 0.02;
float outputDist = Kp_dist * errorDist + Ki_dist * integralDist + Kd_dist * derivativeDist;
float outputAngle = Kp_angle * errorAngle + Ki_angle * integralAngle + Kd_angle * derivativeAngle;
integralDist += errorDist * 0.02;
integralAngle += errorAngle * 0.02;
lastErrorDist = errorDist;
lastErrorAngle = errorAngle;
// 差速控制
float baseSpeed = outputDist * 1.5;
float turnRate = outputAngle * 0.8;
float leftSpeed = baseSpeed - turnRate;
float rightSpeed = baseSpeed + turnRate;
leftMotor.move(leftSpeed);
rightMotor.move(rightSpeed);
// 更新里程计
robotX += (leftSpeed + rightSpeed) * 0.02 * cos(currentAngle) / 2;
robotY += (leftSpeed + rightSpeed) * 0.02 * sin(currentAngle) / 2;
delay(20);
}
2. OpenMV 视觉色块跟随
利用 OpenMV 摄像头识别特定颜色色块,计算机器人与目标的相对位置,使用纯追踪算法控制轮毂电机。OpenMV 通过 UART 发送坐标数据,Arduino 解析后计算预瞄点并控制电机。
#include<SimpleFOC.h>
BLDCMotor leftMotor(7);
BLDCDriver3PWM leftDriver(9,10,11,8);
MagneticSensorI2C leftEncoder(AS5600_I2C);
BLDCMotor rightMotor(12);
BLDCDriver3PWM rightDriver(13,14,15,16);
MagneticSensorI2C rightEncoder(AS5600_I2C);
float targetX = 160, targetY = 120;
float lookaheadRatio = 0.5;
void setup() {
leftMotor.linkSensor(&leftEncoder);
leftMotor.linkDriver(&leftDriver);
leftMotor.controller = MotionControlType::velocity;
leftMotor.initFOC();
rightMotor.linkSensor(&rightEncoder);
rightMotor.linkDriver(&rightDriver);
rightMotor.controller = MotionControlType::velocity;
rightMotor.initFOC();
Serial2.begin(115200);
Serial.begin(115200);
}
void loop() {
// 读取视觉数据
if (Serial2.available() > 0) {
String msg = Serial2.readStringUntil('\n');
int commaIndex = msg.indexOf(',');
targetX = msg.substring(0, commaIndex).toFloat();
targetY = msg.substring(commaIndex + 1).toFloat();
}
// 纯追踪简化版
float imageCenterX = 160, imageCenterY = 120;
float dx = targetX - imageCenterX;
float dy = targetY - imageCenterY;
float angleToTarget = atan2(dy, dx);
float baseSpeed = 2.0;
float turnGain = 0.5;
float errorAngle = angleToTarget;
leftMotor.move(baseSpeed - errorAngle * turnGain);
rightMotor.move(baseSpeed + errorAngle * turnGain);
Serial.print("Target: (");
Serial.print(targetX);
Serial.print(",");
Serial.print(targetY);
Serial.print(") Angle: ");
Serial.println(angleToTarget * 180 / PI);
delay(20);
}
3. 激光雷达 SLAM 跟随
通过 RPLIDAR A1 获取环境点云,使用 SLAM 算法定位机器人与目标,结合路径规划实现动态避障跟随。这需要高性能 MCU(如 Portenta H7)来处理点云数据。
#include<SimpleFOC.h>
#include<RPLidar.h>
BLDCMotor leftMotor(7);
BLDCDriver3PWM leftDriver(9,10,11,8);
MagneticSensorI2C leftEncoder(AS5600_I2C);
BLDCMotor rightMotor(12);
BLDCDriver3PWM rightDriver(13,14,15,16);
MagneticSensorI2C rightEncoder(AS5600_I2C);
RPLidar lidar;
float robotPos[2] = {0, 0};
float targetPos[2] = {2, 0};
float path[100][2];
int pathLength = 0;
void setup() {
leftMotor.linkSensor(&leftEncoder);
leftMotor.linkDriver(&leftDriver);
leftMotor.controller = MotionControlType::velocity;
leftMotor.initFOC();
rightMotor.linkSensor(&rightEncoder);
rightMotor.linkDriver(&rightDriver);
rightMotor.controller = MotionControlType::velocity;
rightMotor.initFOC();
lidar.begin(Serial2);
Serial.begin(115200);
}
void loop() {
if (lidar.available()) {
float scanData[360][2];
lidar.getScan(scanData);
updateSLAM(scanData);
generatePath(robotPos, targetPos, path, &pathLength);
}
if (pathLength > 0) {
Vector2 currentPos(robotPos[0], robotPos[1]);
Vector2 nextPoint(path[0][0], path[0][1]);
float lookaheadDist = 0.3 + (pathLength > 5 ? 0.2 : 0);
Vector2 lookahead = getLookaheadPoint(currentPos, nextPoint, lookaheadDist);
float dx = lookahead.x - robotPos[0];
float dy = lookahead.y - robotPos[1];
float angleToTarget = atan2(dy, dx);
float baseSpeed = 1.5;
float turnRate = angleToTarget * 0.8;
leftMotor.move(baseSpeed - turnRate);
rightMotor.move(baseSpeed + turnRate);
}
delay(20);
}
void updateSLAM(float scanData[360][2]) { /* ... */ }
void generatePath(float start[2], float end[2], float path[100][2], int* length) { /* ... */ }
Vector2 getLookaheadPoint(Vector2 pos, Vector2 next, float dist) { /* ... */ }
4. 超声波恒距平滑跟随
这是最经典的跟随方案。利用超声波测距,通过 PID 算法将距离误差转化为电机速度指令。相比简单的'近了就退,远了就进',PID 能让底盘在接近目标时自动减速,实现平滑停靠。
#include<SimpleFOC.h>
BLDCMotor motorL(7);
BLDCMotor motorR(7);
BLDCDriver3PWM driverL(9,10,11,8);
BLDCDriver3PWM driverR(5,6,7,4);
#define TRIG_PIN 2
#define ECHO_PIN 3
const float TARGET_DIST = 50.0;
const float MAX_DIST = 200.0;
const float MIN_DIST = 20.0;
float Kp = 2.0, Ki = 0.0, Kd = 1.0;
float lastError = 0;
float integral = 0;
void setup() {
Serial.begin(115200);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
driverL.voltage_power_supply = 12;
driverL.init();
motorL.linkDriver(&driverL);
motorL.init();
motorL.initFOC();
driverR.voltage_power_supply = 12;
driverR.init();
motorR.linkDriver(&driverR);
motorR.init();
motorR.initFOC();
}
float readDistance() {
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
long duration = pulseIn(ECHO_PIN, HIGH, 30000);
return (duration * 0.034) / 2;
}
void loop() {
float distance = readDistance();
if (distance > MAX_DIST || distance < 2) {
motorL.move(0);
motorR.move(0);
return;
}
float error = distance - TARGET_DIST;
integral += error;
float derivative = error - lastError;
float speedCmd = (Kp * error) + (Ki * integral) + (Kd * derivative);
lastError = error;
if (abs(speedCmd) < 0.5) speedCmd = 0;
speedCmd = constrain(speedCmd, -5.0, 5.0);
motorL.move(speedCmd);
motorR.move(speedCmd);
motorL.loopFOC();
motorR.loopFOC();
delay(10);
}
5. 蓝牙 RSSI 定向跟随
利用蓝牙模块的信号强度指示(RSSI)来判断目标的远近。这是一种低成本、无需视觉的'盲跟随'方案。需注意不同设备的信号基准差异,必须在实际环境中校准。
#include<SoftwareSerial.h>
SoftwareSerial btSerial(10, 11);
const int RSSI_TARGET = -40;
const int RSSI_TOO_CLOSE = -20;
const int RSSI_TOO_FAR = -70;
const int MOTOR_L_PWM = 9;
const int MOTOR_R_PWM = 10;
const int MOTOR_L_DIR = 2;
const int MOTOR_R_DIR = 3;
void setup() {
Serial.begin(9600);
btSerial.begin(9600);
pinMode(MOTOR_L_PWM, OUTPUT);
pinMode(MOTOR_R_PWM, OUTPUT);
pinMode(MOTOR_L_DIR, OUTPUT);
pinMode(MOTOR_R_DIR, OUTPUT);
}
int readRSSI() {
// 模拟函数,实际需解析 AT+CSQ
return -45;
}
void loop() {
int rssi = readRSSI();
if (rssi == 0) return;
int speed = 0;
if (rssi > RSSI_TOO_CLOSE) {
speed = -100;
digitalWrite(MOTOR_L_DIR, LOW);
digitalWrite(MOTOR_R_DIR, LOW);
} else if (rssi < RSSI_TOO_FAR) {
speed = 150;
digitalWrite(MOTOR_L_DIR, HIGH);
digitalWrite(MOTOR_R_DIR, HIGH);
} else {
speed = map(rssi, RSSI_TOO_FAR, RSSI_TARGET, 150, 0);
digitalWrite(MOTOR_L_DIR, HIGH);
digitalWrite(MOTOR_R_DIR, HIGH);
}
analogWrite(MOTOR_L_PWM, abs(speed));
analogWrite(MOTOR_R_PWM, abs(speed));
Serial.print("RSSI: ");
Serial.print(rssi);
Serial.print(" Speed: ");
Serial.println(speed);
delay(100);
}
6. 多传感器融合防碰撞
单纯的跟随容易发生碰撞。本案例增加了前后双超声波检测,构建了一个简单的'安全包围盒'。一旦检测到前方有突发障碍物或后方有人靠近,立即触发急停或避让逻辑。
#include<NewPing.h>
#define SONAR_NUM 2
#define TRIG_PIN_FRONT 2
#define ECHO_PIN_FRONT 3
#define TRIG_PIN_REAR 4
#define ECHO_PIN_REAR 5
#define MAX_DIST 200
NewPing sonar[SONAR_NUM] = {
NewPing(TRIG_PIN_FRONT, ECHO_PIN_FRONT, MAX_DIST),
NewPing(TRIG_PIN_REAR, ECHO_PIN_REAR, MAX_DIST)
};
const int STOP_DIST_FRONT = 30;
const int STOP_DIST_REAR = 20;
int motorSpeed = 0;
void setup() {
Serial.begin(9600);
}
void setMotors(int left, int right) {
// 驱动电机函数
}
void loop() {
delay(50);
unsigned int distFront = sonar[0].ping_cm();
delay(50);
unsigned int distRear = sonar[1].ping_cm();
if ((distFront > 0 && distFront < STOP_DIST_FRONT) ||
(distRear > 0 && distRear < STOP_DIST_REAR)) {
motorSpeed = 0;
setMotors(0, 0);
Serial.println("⚠️ 障碍物检测!紧急制动");
return;
}
if (distFront > 0 && distFront < MAX_DIST) {
if (distFront > 100) {
motorSpeed = 150;
} else {
motorSpeed = 0;
}
setMotors(motorSpeed, motorSpeed);
}
Serial.print("Front: ");
Serial.print(distFront);
Serial.print(" Rear: ");
Serial.println(distRear);
}
技术总结
轮毂电机的 FOC 控制优势在于极低速下的平稳运行和精准扭矩控制,这对于跟随机器人至关重要,能避免低速跟随时的'顿挫感'。PID 在距离控制中将距离误差转化为速度指令,当距离远时速度快,距离近时速度慢,到达目标距离时速度为 0,这种平滑过渡是提升用户体验的关键。
RSSI 跟随成本极低,但受环境影响大,关键在于校准。多传感器设计中,分时触发超声波传感器可以避免回波串扰。涉及大功率轮毂电机时,惯性很大,刹车距离长,安全冗余机制必须遵循'急停逻辑优先级高于跟随逻辑'的铁律。


