
《Arduino 手册(思路与案例)》栏目介绍:
在电子制作与智能控制的应用领域,本栏目涵盖了丰富的内容,包括但不限于以下主题:Arduino BLDC、Arduino CNC、Arduino E-Ink、Arduino ESP32 SPP、Arduino FreeRTOS、Arduino FOC、Arduino GRBL、Arduino HTTP、Arduino HUB75、Arduino IoT Cloud、Arduino JSON、Arduino LCD、Arduino OLED、Arduino LVGL、Arduino PID、Arduino TFT,以及Arduino智能家居、智慧交通、月球基地、智慧校园和智慧农业等多个方面与领域。不仅探讨了这些技术的基础知识和应用领域,还提供了众多具体的参考案例,帮助读者更好地理解和运用Arduino平台进行创新项目。目前,本栏目已有近4000篇相关博客,旨在为广大电子爱好者和开发者提供全面的学习资源与实践指导。通过这些丰富的案例和思路,读者可以获取灵感,推动自己的创作与开发进程。
https://blog.csdn.net/weixin_41659040/category_12422453.html

Arduino BLDC 之 通过串口控制三关节机械臂
一、主要特点
精准控制:
通过 Arduino 控制 BLDC 电机,实现三关节机械臂的高精度运动,能够在预设的轨迹和位置之间平滑移动,确保机械臂的稳健性和准确性。
串口通信:
采用串口通信(如 UART)实现与计算机或其他控制设备的实时数据传输,使得指令的发送与响应更加高效,适合远程控制和调试。
灵活的运动模式:
支持多种运动模式(如关节空间控制、笛卡尔空间控制),用户可以根据具体任务选择不同的控制方式,增强系统的适应性。
可编程性和扩展性:
用户可以根据需求编写自定义控制程序,轻松实现不同的应用场景和功能,具有良好的扩展性。
实时反馈机制:
通过传感器(如编码器)获取实时反馈,确保机械臂运动的准确性和稳定性,减少误差和偏差。
二、应用场景
工业自动化:
在制造业中,三关节机械臂可用于物品搬运、装配、焊接等任务,提高生产效率和精度。
实验室研究:
在科研实验中,机械臂可用于自动化实验、样品处理等,减轻实验人员的工作负担。
教育与培训:
在工程和机器人教育领域,三关节机械臂是学习自动化控制、机器人技术和编程的理想平台。
医疗设备:
在医疗领域,机械臂可用于手术辅助、康复训练等,提高医疗操作的精确度和安全性。
家庭服务:
在智能家居中,机械臂可以用于执行简单的日常任务,如物品递送、清洁等,提高生活便利性。
三、注意事项
电机选择与配置:
选择适合的 BLDC 电机,确保其具备足够的扭矩和精度,以满足机械臂的运动需求。
控制算法设计:
设计合适的控制算法(如 PID 控制),确保机械臂在运动过程中的平稳性和准确性,避免过冲或振荡。
串口通信稳定性:
确保串口通信的稳定性,避免因通信延迟或数据丢失导致的控制失效,必要时可以实现数据校验机制。
传感器集成:
根据需要选择合适的传感器(如位置传感器、力反馈传感器),提高控制精度和系统反馈能力。
安全性考虑:
在设计和使用过程中考虑机械臂的安全性,设置合理的运动范围和速度限制,避免对人员和设备造成伤害。

1、基础串口控制机械臂
#include <Servo.h>
Servo joint1; // 第一关节
Servo joint2; // 第二关节
Servo joint3; // 第三关节
void setup() {
Serial.begin(9600);
joint1.attach(9); // 第一关节控制引脚
joint2.attach(10); // 第二关节控制引脚
joint3.attach(11); // 第三关节控制引脚
}
void loop() {
if (Serial.available()) {
char command = Serial.read(); // 读取串口命令
switch (command) {
case '1':
joint1.write(90); // 第一关节旋转90°
break;
case '2':
joint1.write(0); // 第一关节旋转0°
break;
case '3':
joint2.write(90); // 第二关节旋转90°
break;
case '4':
joint2.write(0); // 第二关节旋转0°
break;
case '5':
joint3.write(90); // 第三关节旋转90°
break;
case '6':
joint3.write(0); // 第三关节旋转0°
break;
default:
break;
}
}
}
2、基于串口输入的角度控制
#include <Servo.h>
Servo joint1;
Servo joint2;
Servo joint3;
void setup() {
Serial.begin(9600);
joint1.attach(9);
joint2.attach(10);
joint3.attach(11);
}
void loop() {
if (Serial.available()) {
int joint = Serial.parseInt(); // 读取关节编号
int angle = Serial.parseInt(); // 读取角度
switch (joint) {
case 1:
joint1.write(angle); // 设置第一关节角度
break;
case 2:
joint2.write(angle); // 设置第二关节角度
break;
case 3:
joint3.write(angle); // 设置第三关节角度
break;
default:
break;
}
}
}
3、预设动作序列控制
#include <Servo.h>
Servo joint1;
Servo joint2;
Servo joint3;
void setup() {
Serial.begin(9600);
joint1.attach(9);
joint2.attach(10);
joint3.attach(11);
}
void loop() {
if (Serial.available()) {
char command = Serial.read(); // 读取串口命令
if (command == 'a') {
// 动作序列A
joint1.write(0);
joint2.write(90);
joint3.write(180);
delay(1000);
joint1.write(90);
joint2.write(0);
joint3.write(90);
} else if (command == 'b') {
// 动作序列B
joint1.write(180);
joint2.write(90);
joint3.write(0);
delay(1000);
joint1.write(90);
joint2.write(90);
joint3.write(90);
}
}
}
要点解读
串口通信:
所有示例程序通过 Serial 库实现与电脑或其他串口设备的通信。使用 Serial.begin(9600) 来设置串口波特率,确保数据传输稳定。
机械臂关节控制:
使用 Servo 库控制机械臂的三个关节。每个关节通过 attach() 函数连接到 Arduino 的特定引脚,以便进行角度控制。
基础命令控制:
第一个示例通过简单的字符命令(‘1’ 到 ‘6’)来控制每个关节的角度,适合基本的操作场景。
角度控制:
第二个示例允许通过串口输入关节编号和角度,进行更灵活的控制。使用 Serial.parseInt() 读取用户输入的整数值,使得用户可以直接设置关节的具体角度。
预设动作序列:
第三个示例实现了预设动作序列,当接收到特定字符命令(如 ‘a’ 和 ‘b’)时,机械臂会执行一系列动作。这种方式适合需要重复执行特定任务的场景。
延迟控制:
在预设动作序列中,通过 delay() 函数控制动作之间的间隔,确保机械臂在执行每个动作时有足够的时间完成。
可扩展性:
这些示例提供了基础框架,可以根据需求扩展功能。例如,可以通过添加更多的关节、引入传感器反馈(如位置传感器)或使用更复杂的控制算法(如 PID 控制)来提升机械臂的性能和灵活性。

4、基础位置控制(PWM+方向信号)
// 机械臂关节控制引脚定义
#define JOINT1_PWM 9 // 关节1 PWM引脚
#define JOINT1_DIR 8 // 关节1 方向引脚
#define JOINT2_PWM 10
#define JOINT2_DIR 7
#define JOINT3_PWM 11
#define JOINT3_DIR 6
// 关节角度限制(单位:度)
#define J1_MIN 0
#define J1_MAX 180
#define J2_MIN 30
#define J2_MAX 150
#define J3_MIN 10
#define J3_MAX 160
void setup() {
Serial.begin(115200);
// 设置PWM频率为31.25kHz(避免BLDC噪音)
TCCR1B = TCCR1B & 0b11111000 | 0x01; // 引脚9,10
TCCR2B = TCCR2B & 0b11111000 | 0x01; // 引脚11
// 初始化引脚
pinMode(JOINT1_PWM, OUTPUT);
pinMode(JOINT1_DIR, OUTPUT);
pinMode(JOINT2_PWM, OUTPUT);
pinMode(JOINT2_DIR, OUTPUT);
pinMode(JOINT3_PWM, OUTPUT);
pinMode(JOINT3_DIR, OUTPUT);
}
void loop() {
if (Serial.available() >= 12) { // 等待完整指令(3关节×4字节)
if (Serial.read() == 0xAA) { // 帧头校验
// 读取3个关节的角度值(0-255映射到实际角度范围)
int j1 = map(Serial.read(), 0, 255, J1_MIN, J1_MAX);
int j2 = map(Serial.read(), 0, 255, J2_MIN, J2_MAX);
int j3 = map(Serial.read(), 0, 255, J3_MIN, J3_MAX);
// 控制关节1
digitalWrite(JOINT1_DIR, (j1 > 90) ? HIGH : LOW); // 假设90度为中立点
analogWrite(JOINT1_PWM, map(abs(j1-90), 0, 90, 0, 255));
// 控制关节2(类似处理)
digitalWrite(JOINT2_DIR, (j2 > 90) ? HIGH : LOW);
analogWrite(JOINT2_PWM, map(abs(j2-90), 0, 60, 0, 255));
// 控制关节3
digitalWrite(JOINT3_DIR, (j3 > 85) ? HIGH : LOW);
analogWrite(JOINT3_PWM, map(abs(j3-85), 0, 75, 0, 255));
// 发送确认回执
Serial.write(0x55);
}
}
}
要点解读:
PWM频率优化:通过修改定时器寄存器将频率提升至31.25kHz,减少BLDC电机噪音
安全限位:通过宏定义限制关节活动范围,防止机械结构损坏
协议设计:使用0xAA帧头+3字节数据+0x55确认的简单协议
方向控制:通过比较目标角度与中立点(如90度)决定旋转方向
5、轨迹插补控制(接收G代码)
#include <math.h>
// 全局变量
float currentPos[3] = {90, 90, 90}; // 初始位置(中立点)
float targetPos[3];
unsigned long stepTime = 0;
bool motionComplete = true;
void setup() {
Serial.begin(115200);
// 引脚初始化同案例一
}
void loop() {
// 1. 解析G代码指令
if (Serial.available()) {
String cmd = Serial.readStringUntil('\n');
if (cmd.startsWith("G1")) { // 线性插补指令
parseGCode(cmd);
motionComplete = false;
stepTime = millis();
}
}
// 2. 执行轨迹插补(每50ms更新一次)
if (!motionComplete && millis() - stepTime >= 50) {
bool allArrived = true;
for (int i=0; i<3; i++) {
if (abs(currentPos[i] - targetPos[i]) > 0.5) {
currentPos[i] += (targetPos[i] > currentPos[i]) ? 0.5 : -0.5;
allArrived = false;
}
}
// 更新电机输出
updateMotors();
if (allArrived) {
motionComplete = true;
Serial.println("OK"); // 运动完成反馈
}
stepTime = millis();
}
}
void parseGCode(String cmd) {
// 示例指令:G1 X120 Y80 Z50 F1000
if (cmd.indexOf('X') != -1) {
targetPos[0] = cmd.substring(cmd.indexOf('X')+1).toFloat();
targetPos[0] = constrain(targetPos[0], J1_MIN, J1_MAX);
}
// Y/Z参数类似处理...
}
void updateMotors() {
// 关节1控制(带正弦加速曲线)
float progress = sin(min(1.0, (millis()-stepTime)/1000.0) * PI/2);
int pwm = map(currentPos[0], J1_MIN, J1_MAX, 0, 255) * progress;
digitalWrite(JOINT1_DIR, (currentPos[0] > 90) ? HIGH : LOW);
analogWrite(JOINT1_PWM, pwm);
// 关节2/3类似处理...
}
要点解读:
G代码支持:实现类似3D打印机的指令系统(G1 Xnn Ynn Znn)
轨迹平滑:使用正弦函数实现加速曲线,避免运动冲击
增量式控制:每次更新0.5度,平衡精度与响应速度
状态反馈:运动完成后发送"OK"确认
6、力矩控制模式(需电流检测)
// 电流检测相关
#define CURRENT_SENSOR A0
#define JOINT1_CURRENT_LIMIT 1500 // mA
// PID参数
float Kp = 0.8, Ki = 0.1, Kd = 0.05;
float errorSum[3] = {0};
float lastError[3] = {0};
void setup() {
Serial.begin(115200);
analogReference(EXTERNAL); // 使用外部参考电压提高精度
}
void loop() {
static unsigned long lastPID = 0;
if (millis() - lastPID >= 10) { // 100Hz PID循环
for (int i=0; i<3; i++) {
// 1. 读取目标位置(通过串口实时更新)
float target = currentPos[i]; // 实际应用应从串口获取
// 2. 读取当前位置(需编码器反馈)
float current = readEncoder(i); // 伪代码,需实际实现
// 3. PID计算
float error = target - current;
errorSum[i] += error;
float delta = error - lastError[i];
lastError[i] = error;
// 4. 电流限制
float output = Kp*error + Ki*errorSum[i] + Kd*delta;
int pwm = constrain(abs(output), 0, 255);
// 5. 电流检测与保护
int currentRead = analogRead(CURRENT_SENSOR);
if (currentRead > JOINT1_CURRENT_LIMIT) {
pwm = 0; // 过流保护
Serial.println("WARNING: Overcurrent!");
}
// 6. 更新电机
digitalWrite(JOINT1_DIR, (output > 0) ? HIGH : LOW);
analogWrite(JOINT1_PWM, pwm);
}
lastPID = millis();
}
// 串口调试接口
if (Serial.available()) {
String cmd = Serial.readStringUntil('\n');
if (cmd.startsWith("SET")) {
// 示例指令:SET 1 120.5 (关节1目标120.5度)
int joint = cmd.substring(4,5).toInt();
float angle = cmd.substring(6).toFloat();
if (joint >=1 && joint <=3) {
currentPos[joint-1] = constrain(angle,
(joint==1)?J1_MIN:(joint==2)?J2_MIN:J3_MIN,
(joint==1)?J1_MAX:(joint==2)?J2_MAX:J3_MAX);
}
}
}
}
要点解读:
电流闭环:通过电流检测实现力矩限制,保护机械结构
PID控制:实现位置闭环控制,需配合编码器反馈
动态参数调整:可通过串口发送"PID Kp0.8 Ki0.1 Kd0.05"调整参数
保护机制:过流时立即停止输出并报警
注意,以上案例只是为了拓展思路,仅供参考。它们可能有错误、不适用或者无法编译。您的硬件平台、使用场景和Arduino版本可能影响使用方法的选择。实际编程时,您要根据自己的硬件配置、使用场景和具体需求进行调整,并多次实际测试。您还要正确连接硬件,了解所用传感器和设备的规范和特性。涉及硬件操作的代码,您要在使用前确认引脚和电平等参数的正确性和安全性。


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



