ESP32开源5自由度机械臂制作
·
ESP32 5自由度机械臂制作实录:从硬件到代码的完整旅程
前言
最近我完成了一个基于ESP32的5自由度机械臂控制系统,这个项目结合了硬件设计和软件开发,让我深入学习了ESP-IDF框架、舵机控制、运动学计算以及Web界面开发等多方面知识。今天想和大家分享这个项目的制作过程和关键技术点。
项目概述
这是一个基于ESP32-WROOM和PCA9685的5自由度机械臂控制系统,使用ESP-IDF框架开发。机械臂结构参考了一个开源项目,系统支持Web界面控制、学习模式和路径管理功能。
硬件准备
主要组件
- ESP32-WROOM开发板(大脑)
- PCA9685 16通道PWM控制器(控制舵机)
- 5个舵机(1个MG996R底座舵机,3个关节舵机,1个SG90夹爪舵机)
- 5V/2A电源(舵机需要足够电流)
- 结构件(开源项目 https://www.youtube.com/watch?v=5toNqaGsGYs)
组装过程
- 首先组装机械臂结构,将各关节舵机固定到相应位置
- 连接ESP32和PCA9685:GPIO21→SDA,GPIO22→SCL
- 将舵机按顺序连接到PCA9685的通道0-4
- 为舵机提供单独的5V电源(舵机耗电大,不能直接使用ESP32供电)
软件架构设计
项目采用组件化设计,主要包含以下几个组件:
- pca9685:负责与PCA9685芯片通信,生成PWM信号
- servo_controller:舵机控制抽象层,处理角度转换和平滑移动
- robotic_arm:机械臂控制核心,包含运动学计算
- learning_controller:实现路径学习和回放功能
- web_controller:提供Web界面和WiFi连接功能
关键技术点解析
1. I2C通信与PCA9685驱动
PCA9685是通过I2C总线控制的,ESP32作为主机需要初始化I2C总线并与PCA9685通信:
// I2C初始化
i2c_config_t conf = {
.mode = I2C_MODE_MASTER,
.sda_io_num = I2C_SDA_PIN,
.scl_io_num = I2C_SCL_PIN,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = I2C_FREQ_HZ
};
i2c_param_config(I2C_NUM_0, &conf);
i2c_driver_install(I2C_NUM_0, conf.mode, 0, 0, 0);
2. 舵机控制算法
舵机控制需要将角度转换为适当的PWM脉冲宽度,并实现平滑移动:
// 角度到脉冲宽度的转换
uint16_t servo_angle_to_pulse(servo_config_t *config, float angle) {
if (angle < config->min_angle) angle = config->min_angle;
if (angle > config->max_angle) angle = config->max_angle;
return config->min_pulse + (angle - config->min_angle) *
(config->max_pulse - config->min_pulse) /
(config->max_angle - config->min_angle);
}
3. 正逆运动学计算
机械臂的运动学计算是核心难点,需要实现:
- 正运动学:根据关节角度计算末端位置
- 逆运动学:根据末端位置计算各关节角度
// 逆运动学示例(简化版)
bool inverse_kinematics(float x, float y, float z, float *base, float *shoulder, float *elbow) {
// 计算底座角度
*base = atan2(y, x) * RAD_TO_DEG;
// 计算到末端的距离
float r = sqrt(x*x + y*y) - WRIST_LENGTH;
float d = sqrt(r*r + (z-BASE_HEIGHT)*(z-BASE_HEIGHT));
// 检查是否超出机械臂的工作范围
if (d > ARM_LENGTH + FOREARM_LENGTH || d < fabs(ARM_LENGTH - FOREARM_LENGTH)) {
return false; // 位置不可达
}
// 使用余弦定理计算肩部和肘部角度
float cos_elbow = (ARM_LENGTH*ARM_LENGTH + FOREARM_LENGTH*FOREARM_LENGTH - d*d) /
(2 * ARM_LENGTH * FOREARM_LENGTH);
*elbow = (180.0f - acos(cos_elbow) * RAD_TO_DEG);
// 计算肩部角度
float beta = acos((ARM_LENGTH*ARM_LENGTH + d*d - FOREARM_LENGTH*FOREARM_LENGTH) /
(2 * ARM_LENGTH * d)) * RAD_TO_DEG;
*shoulder = atan2(z-BASE_HEIGHT, r) * RAD_TO_DEG + beta;
return true;
}
4. Web界面与WebSocket实时通信
Web界面使用HTML/CSS/JavaScript实现,与ESP32通过WebSocket通信,实现实时控制:
// WebSocket连接示例
const socket = new WebSocket(`ws://${window.location.hostname}/ws`);
socket.onopen = function() {
console.log("WebSocket连接已建立");
};
socket.onmessage = function(event) {
const data = JSON.parse(event.data);
updateServoPositions(data);
};
// 发送控制命令
function sendServoCommand(servoId, angle) {
socket.send(JSON.stringify({
type: "servo_control",
servo: servoId,
angle: angle
}));
}
5. 学习模式与路径存储
学习模式使用NVS(Non-Volatile Storage)保存路径数据:
// 将路径保存到NVS
esp_err_t save_path_to_nvs(int path_index, servo_path_t *path) {
nvs_handle_t nvs_handle;
esp_err_t err = nvs_open("servo_paths", NVS_READWRITE, &nvs_handle);
if (err != ESP_OK) return err;
char key[16];
sprintf(key, "path_%d", path_index);
// 保存路径元数据
nvs_set_u16(nvs_handle, key, path->point_count);
// 保存各个路径点
for (int i = 0; i < path->point_count; i++) {
char point_key[32];
sprintf(point_key, "path_%d_p%d", path_index, i);
nvs_set_blob(nvs_handle, point_key, &path->points[i], sizeof(servo_point_t));
}
nvs_commit(nvs_handle);
nvs_close(nvs_handle);
return ESP_OK;
}
制作过程中的挑战与解决方案
1. 舵机抖动问题
舵机在静止状态下仍有抖动,影响精度。
解决方案:
- 调整PWM频率至50Hz
- 实现舵机平滑移动算法,通过小步进移动
- 添加死区判断,微小角度变化不驱动舵机
2. 运动学计算精度问题
初期机械臂运动不精确,特别是在某些位置。
解决方案:
- 精确测量每个连杆的实际长度
- 对舵机进行校准,确定实际的最小/最大脉宽
- 修正运动学模型中的偏移量
后续改进计划
- 添加基于摄像头的视觉识别功能
- 实现更复杂的路径规划算法
- 开发手机APP控制界面
- 添加语音控制功能
这个项目既有挑战性又很有成就感,希望我的分享能对有兴趣开发类似项目的朋友有所帮助!
开源地址:https://github.com/1730490023/ESP32_WROOM_IDF_Rebot_wifi.git
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)