桌面机械臂:多舵机协调抓取小物件
- 做出一台四到六自由度、能抓起橡皮/瓶盖这类小物的桌面机械臂
- 把多舵机驱动(PCA9685)和角度控制两个单练的知识点接成一条完整的“抓取动作链”
- 学会正确接线:PCA9685 走 I2C、舵机走独立 5V、全系统共地,避开供电拖垮主控的坑
- 用 ESP-IDF 分三步长出代码:控单舵机 → 多舵机协调插值 → 摇杆/预设动作抓取
- 想清一台多舵机设备“同时要动几个关节”时,动作该怎么组织、怎么排上电顺序
| 器材 | 数量 | 参考 |
|---|---|---|
| 4-6 自由度机械臂支架(金属或亚克力套件,含舵机位) | 1 套 | —约 50-120 元(以商城实际为准) |
| 舵机(SG90 小力矩练手,或 MG996R 金属齿带得动负载) | 4-6 | —SG90 约 5-10 元/个、MG996R 约 15-30 元/个(以商城实际为准) |
| PCA9685 16 路 PWM/舵机驱动模块 | 1 | —约 8-18 元(以商城实际为准) |
| 独立 5V 大电流电源(适配器 5V/3A 以上,或足够的电池组) | 1 | —约 15-40 元(以商城实际为准) |
| 电位器或双轴摇杆模块(做手动遥控用) | 1-2 | —约 2-8 元(以商城实际为准) |
| ESP32-S3 开发板 + 杜邦线若干 | 1 套 | —约 25-45 元(以商城实际为准) |
价格随渠道波动,以购买页实时为准。
桌上摆着一只巴掌高的小机械臂。你推一下摇杆,它的底座缓缓转过去,大臂放下、小臂探出,夹爪张开对准一块橡皮,轻轻一合——夹住了;你再一推,它把橡皮拎起来、转个方向、松开,稳稳放到另一边。没有电脑连着,没有 App,一根摇杆就把六个关节指挥明白了。这就是这个项目要带你做出来的东西。
它不是玩具展示,是你第一次把两件事真正拧成一股绳:用 PCA9685 一次驱动一堆舵机,和让这些舵机按先后、按节奏协调着动出一个有意义的抓取。之前你在 舵机入门让单个舵机听话地转到某个角度,在 用 PCA9685 一次驱动 16 个舵机解决了“多舵机怎么接、怎么供电不重启”,但那还只是让它们“一个个轮流动”。这一篇把它们组织成一台能干活的机械臂——这个“组织”,就是 project 比前面那些知识点多出来的一层功夫。
这篇不重复讲 PCA9685 的 I2C 原理、脉宽换算——那些 robot-servo-pca9685 已经讲透,这里默认你跑通过“让多个舵机依次扫动”那一步。我们只干一件事:把它拼成一台会抓东西的机械臂,讲清拼的过程里那些单看一个舵机时看不到的坑。
多舵机机械臂,电和手是两条命门,先钉死再动手:
- 舵机电源必须走独立 5V,绝不从开发板取电。 一个 MG996R 堵转(转不动还硬顶)瞬时电流能冲过 1A,四到六个同时启动或同时堵转就是好几安培。你要是图省事把舵机正极接到板子的 5V/VIN,稳压器供不出这么大电流,电压被瞬间拉垮,主控欠压复位——现象就是机械臂一动板子就重启,查一晚上代码其实一行没错,是电不够。容量按「舵机数 × 单个堵转电流」估,六个 MG996R 至少备 5V/6A。
- 独立 5V 电源的地,必须和 ESP32 的 GND 接到一起(共地)。 不共地,I2C 电平没有共同参考,命令根本发不进 PCA9685,舵机不动,严重时还会烧逻辑。
- 机械臂运动会夹手、会甩。 上电瞬间通道是随机历史值,臂会猛弹一下,别把手、脸、桌上易碎物放在扫动范围里;调试时把电源开关攥在手边,一见姿态失控立刻断电。夹爪合拢力气不小,别拿它夹手指试。
- 别让舵机长时间硬顶机械极限。 堵转既烧舵机也烧驱动板,代码里务必给每个关节做角度钳位,别让它撞到结构死点还在使劲。
第一步:想清楚要做成什么样,再定选型
动手前先把“成品长什么样”钉死,选型才有依据。我们的机械臂就一条主线行为:把一个小物件从 A 点抓起、搬到 B 点、放下。 拆开来是四个自由度起步:
- 底座旋转:整条臂左右转,决定抓取方向。
- 大臂俯仰:控制臂伸出去的远近高低。
- 小臂俯仰:配合大臂让末端够到目标。
- 夹爪开合:张开对准、合拢夹住。
想更灵活可以加到六个(多一个手腕俯仰、一个手腕旋转),但先用四个把整条链路跑通,多的自由度是锦上添花,不是入门必需。行为定了,选型每一步就都有理由。
舵机:SG90 还是 MG996R?
这是你要做的第一个取舍:
| SG90(塑料齿) | MG996R(金属齿) | |
|---|---|---|
| 力矩 | 小,约 1.5kg·cm | 大,约 10kg·cm |
| 带负载 | 只能带很轻的臂和小物 | 能带得动金属臂+像样的负载 |
| 价格 | 便宜一半以上 | 略贵 |
| 发热/堵转 | 堵转电流小些 | 堵转电流大,供电要求更高 |
| 适合 | 纯练手、轻质亚克力臂 | 想真抓点有分量的东西 |
一句话决策:纯练逻辑、臂很轻,用 SG90 便宜省事;想让它真夹起有点分量的东西、臂是金属的,底座和大臂这两个吃力的关节至少上 MG996R。 常见做法是混搭——吃力的大臂、底座用 MG996R,末端的小臂、夹爪用 SG90 减重。它们的控制接口完全一样(都是 50Hz PWM、脉宽定角度),代码一个字不用改,只是脉宽边界可能各自微调。
为什么必须用 PCA9685,不直接用 ESP32 的 GPIO?
你可能想:ESP32-S3 的 LEDC 不是有 PWM 吗,直接生成四路舵机信号不行?会撞两堵墙,这也是 robot-servo-pca9685 讲透的:
- 通道和定时器排布别扭。LEDC 要给每路都配 50Hz 低频又保证脉宽分辨率,四路以上排起来乱,还要占用宝贵的定时器资源。
- 更致命的是供电——但这堵墙其实不是 PCA9685 “算力”解决的,是它把舵机电源引到独立的 V+ 端子、和逻辑电源彻底分家解决的。
PCA9685 的真正价值是把「控制」和「供电」分了家:控制走 I2C 两根线(主控只发命令),供电走独立 5V 灌进 V+。主控只动嘴皮子,重活它不碰。做机械臂、六足、人形,这是标准做法,不是可选项。
第二步:接线——四类线,避开雷区
这是整个项目最容易翻车的地方,照着来。分四类:控制线、逻辑供电、舵机独立供电、舵机信号。
控制侧(ESP32-S3 ↔ PCA9685,走 I2C):
| PCA9685 引脚 | 接到 ESP32-S3 | 作用 |
|---|---|---|
| VCC | 3.3V | 芯片逻辑供电,不是给舵机的 |
| GND | GND | 逻辑地 |
| SDA | GPIO8(以你板子丝印为准) | I2C 数据 |
| SCL | GPIO9(以你板子丝印为准) | I2C 时钟 |
ESP32-S3 的 I2C 引脚可以软件指定,但选脚仍有雷区,接线前对照排除:
- GPIO0 / 3 / 45 / 46:strapping 脚,上电电平决定启动模式,接了外设可能刷不进、起不来;
- GPIO26-37:绝大多数模组内部连着 SPI flash / PSRAM,动了直接死机;
- GPIO19 / 20:默认 USB D-/D+,占用会断掉 USB 串口,日志都看不到;
- GPIO22 / 23 / 24 / 25:S3 上根本不存在这几个号(GPIO 号从 21 直接跳到 26,中间是空的),写了编译不报错、运行时行为诡异。
GPIO8 / GPIO9 都在安全区,本项目用它俩做 I2C。你板子丝印标了别的 SDA/SCL 就跟丝印走,代码里 i2c_master 初始化时填对应号即可。
舵机独立供电侧(关键,别接错):
- PCA9685 的
V+端子接独立 5V 电源正极(5V/3A 以上适配器,或足够的电池组)。这路专喂舵机。 - 这个 5V 电源的地,必须和 ESP32 的 GND 接到一起——这就是共地。不共地 I2C 不工作。
- 别把 V+ 和 VCC 搞混:VCC 是给芯片逻辑的 3.3V,V+ 才是给舵机的 5V 大电流。接反了要么舵机不动,要么烧板。
舵机信号侧:
- 每个舵机的三根线(信号/正/负)直接插 PCA9685 对应通道的排针,有防呆方向,黑(或棕)线朝 GND 那一侧,别插反。
- 通道分配建议固定下来,代码里对应:底座=0、大臂=1、小臂=2、夹爪=3(加自由度就 4、5 顺延)。
接线拓扑一眼图:
ESP32-S3 ──GPIO8(SDA)/GPIO9(SCL)──▶ PCA9685 (VCC←3.3V, GND←共地)
│
独立 5V 电源 ──(+)──▶ V+ 端子 ├─ 通道0 ── 底座舵机
──(−)──┐ ├─ 通道1 ── 大臂舵机
│ ├─ 通道2 ── 小臂舵机
ESP32-S3 GND ───────┴─ 共地 └─ 通道3 ── 夹爪舵机
记住这条铁律:舵机的电永远从 V+ 那路独立电源来,绝不从主控取;所有地必须共到一起。
第三步:分步把代码写出来
我们不一次甩一大段,而是分三步长出来,每步都能单独烧进去看到效果——出问题时你才知道是哪一步坏的。这里用 ESP-IDF 原生的 i2c_master 直接跟 PCA9685 通信(不依赖 Arduino 库),把寄存器怎么配讲清楚。
步 1:先让一个舵机通过 PCA9685 转起来
第一步只验证一件事:I2C 通了、PCA9685 认到了、50Hz 配对了、单个舵机能到位。PCA9685 的核心就三步:设分频得到 50Hz、往某通道的 4 个寄存器写“开始/结束计数”、角度换算成计数值。
#include "driver/i2c_master.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
static const char *TAG = "arm";
#define I2C_PORT I2C_NUM_0
#define PIN_SDA GPIO_NUM_8 // 避开雷区,以丝印为准
#define PIN_SCL GPIO_NUM_9
#define PCA9685_ADDR 0x40 // 一块板不焊地址跳线就是 0x40
// PCA9685 寄存器
#define REG_MODE1 0x00
#define REG_PRESCALE 0xFE
#define REG_LED0_ON_L 0x06 // 通道 0 的第一个寄存器,每通道占 4 个
// 舵机参数:50Hz 周期 20ms;脉宽 500us=0°,2500us=180°(不同舵机后面校准)
#define SERVO_FREQ 50
#define SERVO_MIN_US 500
#define SERVO_MAX_US 2500
static i2c_master_dev_handle_t s_dev;
static void pca_write(uint8_t reg, uint8_t val)
{
uint8_t buf[2] = { reg, val };
ESP_ERROR_CHECK(i2c_master_transmit(s_dev, buf, sizeof(buf), 100));
}
// 设某通道的 PWM:on 一般给 0,off 是脉宽对应的计数值(0~4095)
static void pca_set_pwm(uint8_t ch, uint16_t off)
{
uint8_t base = REG_LED0_ON_L + 4 * ch;
uint8_t buf[5] = { base, 0x00, 0x00, (uint8_t)(off & 0xFF), (uint8_t)(off >> 8) };
ESP_ERROR_CHECK(i2c_master_transmit(s_dev, buf, sizeof(buf), 100));
}
// 微秒脉宽 → 12 位计数:一个 20000us 周期切成 4096 份
static uint16_t us_to_ticks(int us)
{
return (uint16_t)((long)us * 4096 / 20000);
}
// 给某通道设角度(带钳位,防止顶到机械极限)
static void set_angle(uint8_t ch, int deg)
{
if (deg < 0) deg = 0;
if (deg > 180) deg = 180;
int us = SERVO_MIN_US + (SERVO_MAX_US - SERVO_MIN_US) * deg / 180;
pca_set_pwm(ch, us_to_ticks(us));
}
static void pca_init(void)
{
i2c_master_bus_config_t bus = {
.i2c_port = I2C_PORT,
.sda_io_num = PIN_SDA,
.scl_io_num = PIN_SCL,
.clk_source = I2C_CLK_SRC_DEFAULT,
.glitch_ignore_cnt = 7,
.flags.enable_internal_pullup = true, // 模块通常自带上拉,这里再兜个底
};
i2c_master_bus_handle_t bus_h;
ESP_ERROR_CHECK(i2c_new_master_bus(&bus, &bus_h));
i2c_device_config_t dev = {
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
.device_address = PCA9685_ADDR,
.scl_speed_hz = 400000, // 400kHz 快速模式
};
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_h, &dev, &s_dev));
// 设 50Hz:prescale = round(25MHz / (4096 * 50)) - 1 = 121
pca_write(REG_MODE1, 0x10); // 先进 sleep 才能改 prescale
pca_write(REG_PRESCALE, 121); // 50Hz
pca_write(REG_MODE1, 0x00); // 唤醒
vTaskDelay(pdMS_TO_TICKS(5)); // 唤醒后等振荡器稳
pca_write(REG_MODE1, 0xA0); // 开自动递增 + 重启
}
void app_main(void)
{
pca_init();
ESP_LOGI(TAG, "PCA9685 就绪,测试底座舵机(通道0)");
while (1) {
set_angle(0, 60); vTaskDelay(pdMS_TO_TICKS(800));
set_angle(0, 120); vTaskDelay(pdMS_TO_TICKS(800));
set_angle(0, 90); vTaskDelay(pdMS_TO_TICKS(800));
}
}
烧进去 idf.py build flash monitor。你应该看到:串口打出“PCA9685 就绪”,底座那个舵机在 60°、120°、90° 之间稳稳来回转,主控不重启。看到这个,说明 I2C 通路、50Hz 配置、供电分离三件事全对——这一步的意义就是把最容易错的地方先隔离验证掉。
这里把
set_angle(ch, deg)封成一个函数,后面所有动作全靠它,不再到处手写换算。为什么?因为机械臂要在几十处改角度,每处都手写脉宽换算既啰嗦又容易错。封一次,后面只调set_angle。这就是从「跑通例子」到「写成品」的第一个思维转变:把易错、重复的换算收进函数。
步 2:多舵机协调——平滑插值,别一步到位
现在把四个舵机都接上,让它们协调地、平滑地动到一组目标角度,而不是各自“啪”地弹过去。机械臂最忌讳一步到位——猛地弹过去既甩得厉害、又容易撞坏结构、瞬时电流也大。做法是插值:把当前角度到目标角度分成很多小步,每步动一点点。
// 四个关节的当前角度,全局记着
static int g_pose[4] = {90, 90, 90, 90}; // 底座/大臂/小臂/夹爪,上电居中
// 把整条臂平滑移动到一组目标姿态。step 越小越顺滑,delay 越大越慢
static void move_to(const int target[4], int step, int delay_ms)
{
bool moving = true;
while (moving) {
moving = false;
for (int i = 0; i < 4; i++) {
if (g_pose[i] < target[i]) {
g_pose[i] += step;
if (g_pose[i] > target[i]) g_pose[i] = target[i];
moving = true;
} else if (g_pose[i] > target[i]) {
g_pose[i] -= step;
if (g_pose[i] < target[i]) g_pose[i] = target[i];
moving = true;
}
set_angle(i, g_pose[i]);
}
vTaskDelay(pdMS_TO_TICKS(delay_ms));
}
}
void app_main(void)
{
pca_init();
// 上电先让每个关节都回到已知的居中姿态,避免从随机位置猛弹
for (int i = 0; i < 4; i++) set_angle(i, g_pose[i]);
vTaskDelay(pdMS_TO_TICKS(500));
ESP_LOGI(TAG, "开始多关节协调动作");
// 两组姿态之间来回:伸出去 / 收回来
int reach[4] = {60, 120, 60, 90}; // 底座偏左、大臂放下、小臂探出、夹爪半开
int home[4] = {90, 90, 90, 90};
while (1) {
move_to(reach, 2, 15); // 2° 一步、每步 15ms,肉眼看着很顺
vTaskDelay(pdMS_TO_TICKS(600));
move_to(home, 2, 15);
vTaskDelay(pdMS_TO_TICKS(600));
}
}
你应该看到:四个关节同时、平滑地从居中姿态过渡到“伸出去”那组角度,停一下再一起收回来,全程动作绵软不甩、主控不重启。step 调大动作更快更急,delay_ms 调大更慢更稳——想要什么手感自己试。
move_to的精髓是让所有关节一起逼近各自的目标、谁先到谁停住。为什么不能一个关节动完再动下一个?那样臂是“折线式”地一节一节挪,既慢又难看,中间还可能撞到桌面。让它们并行插值,整条臂就是一个协调的整体在移动——这是多舵机设备的第二个成品级思维:多个执行器不是轮流动,是配着一起动。
步 3:接上摇杆,或跑预设动作,完成一次真抓取
最后一步把“抓取”做出来。给你两条路,任选或都做:
路 A:预设动作序列(无需额外硬件,先跑通抓取逻辑)。 把一次完整抓取拆成几帧姿态,按顺序 move_to 过去:
// 一次完整抓取:对准 → 下探 → 合爪 → 提起 → 转向 → 松爪 → 复位
static void grab_sequence(void)
{
// 夹爪:60=张开,130=合拢夹紧(按你的夹爪结构调)
int aim[4] = {60, 100, 70, 60}; // 转向目标、探到物件上方、爪张开
int down[4] = {60, 120, 60, 60}; // 大臂再放下一点,够到物件
int grip[4] = {60, 120, 60, 130}; // 只动夹爪:合拢夹住
int lift[4] = {60, 90, 90, 130}; // 抬起来,夹着不松
int turn[4] = {120, 90, 90, 130}; // 底座转到 B 点上方
int release[4]= {120, 90, 90, 60}; // 松爪放下
int home[4] = {90, 90, 90, 90};
move_to(aim, 2, 15); vTaskDelay(pdMS_TO_TICKS(300));
move_to(down, 1, 20); vTaskDelay(pdMS_TO_TICKS(300)); // 下探用更小步长,更稳
move_to(grip, 2, 25); vTaskDelay(pdMS_TO_TICKS(400)); // 合爪慢一点,夹稳
move_to(lift, 2, 15); vTaskDelay(pdMS_TO_TICKS(300));
move_to(turn, 2, 15); vTaskDelay(pdMS_TO_TICKS(300));
move_to(release,2, 20); vTaskDelay(pdMS_TO_TICKS(300));
move_to(home, 2, 15); vTaskDelay(pdMS_TO_TICKS(800));
}
路 B:摇杆手动遥控。 用一个双轴摇杆(本质是两个电位器)控底座和大臂,另一个电位器或按键控夹爪。摇杆的两轴接 ESP32-S3 的 ADC 脚(选支持 ADC1 的安全脚,比如 GPIO4/5),读到的模拟值映射成角度:
#include "esp_adc/adc_oneshot.h"
// 假设摇杆 X 轴接 ADC1 通道,读值 0~4095 映射到底座 0~180°
static adc_oneshot_unit_handle_t s_adc;
static void joystick_init(void)
{
adc_oneshot_unit_init_cfg_t ucfg = { .unit_id = ADC_UNIT_1 };
ESP_ERROR_CHECK(adc_oneshot_new_unit(&ucfg, &s_adc));
adc_oneshot_chan_cfg_t ccfg = { .atten = ADC_ATTEN_DB_12, .bitwidth = ADC_BITWIDTH_DEFAULT };
ESP_ERROR_CHECK(adc_oneshot_config_channel(s_adc, ADC_CHANNEL_3, &ccfg)); // 以你的脚为准
}
static void joystick_task(void *arg)
{
while (1) {
int raw = 0;
adc_oneshot_read(s_adc, ADC_CHANNEL_3, &raw);
int deg = raw * 180 / 4095; // 0~4095 线性映射到 0~180°
// 加一点死区/平滑,摇杆中位附近别抖(这里从略,进阶再优化)
set_angle(0, deg); // 实时控底座
g_pose[0] = deg;
vTaskDelay(pdMS_TO_TICKS(20)); // 50Hz 刷新,跟舵机节奏一致
}
}
你应该看到:路 A 下,机械臂自己走完“对准→下探→夹住→提起→转向→松开→复位”一整套,真能把桌上一块橡皮从左边搬到右边;路 B 下,你推摇杆哪个方向,对应关节就跟着实时转,像遥控挖掘机那样手动去够、去夹。
到这里核心功能全齐了。回头看,你没写多少新东西:I2C 和脉宽换算是 robot-servo-pca9685 的,ADC 读摇杆是外设课的,你干的是用插值把多个舵机组织成协调动作、再把动作串成一次抓取——这个“组织动作”,就是机械臂比“驱动舵机”多出来的那层功夫。
第四步:调试——对不上就查这张表
分步烧的好处是,哪一步出问题你已经缩小了范围。真出了岔子,照这张表查:
| 现象 | 最可能的原因 | 怎么办 |
|---|---|---|
| 舵机抖动、嗡嗡响、不停微动 | 独立 5V 电流不足或电压不稳 / 共地不良 | 换更大电流的独立电源;确认独立电源地和主控地真的共到一起;线材太细换粗 |
| 一让多个关节动主控就重启 | 舵机在从主控取电,把主控拖欠压 | 舵机供电走独立 V+,绝不从主控 5V/VIN 取;确认共地;见 safety 框第一条 |
| 舵机完全不动、串口正常 | V+ 没接独立电源,或接到了 VCC | V+ 必须接独立 5V,VCC 只是 3.3V 逻辑供电,两者别搞混 |
| 串口报 I2C 找不到设备 / 卡住 | SDA/SCL 接反、地址不对、没上拉 | 核对 SDA/SCL 和板子丝印;确认地址 0x40(没焊跳线);模块通常自带上拉,没有就补 |
| 某关节角度不准、0° 不到位或过头 | 该型号舵机脉宽边界和 500/2500us 不一致 | 微调该舵机的 SERVO_MIN_US/SERVO_MAX_US,逐个试到位;混装 SG90/MG996R 时更要分开校 |
| 上电瞬间机械臂猛甩一下 | 通道是随机历史值 | pca_init 后先把每个关节 set_angle 到居中姿态再开始动作(步 2 已这么做) |
| 动作到某处“咔咔”响、卡住 | 目标角度顶到了机械死点 | 缩小该关节的角度范围,别让它撞结构;给 set_angle 之外再加一层每关节的安全上下限 |
| 夹爪夹不住 / 夹太狠变形 | 合拢角度不对 | 逐度试出“刚好夹紧”那个角度,别直接给 180°,夹爪结构受力大 |
| 插值动作一顿一顿不平滑 | step 太大或 delay_ms 太小被任务抢占 |
减小 step(如 1°)、适当加 delay_ms;别把重活塞进动作循环 |
一次只改一处再烧。同时改三个关节的角度、臂还是不对,你根本分不清是哪个改动的锅。分步烧、单点改,是硬件调试省时间的铁律。调机械臂尤其如此——先单独把每个关节的“到位角度”一个个校准好记下来,再拼进动作序列。
第五步:从“能抓”到“抓得准、抓得聪明”
到这它已经是台能抓东西的机械臂了。但“能抓”和“抓得准、抓得稳”之间还差几步——正好通向后面的阶梯,先给你指条路。
让它抓向空间里的某个点:逆运动学
现在你是手动一个个试关节角度凑出抓取姿态。真正的机械臂要的是:告诉它“去抓桌面上 (x, y, z) 那个点”,它自己算出每个关节该转多少度。这个“从末端位置反算关节角度”的过程叫逆运动学,是机械臂从“摆造型”升级到“按坐标干活”的分水岭。这块硬骨头单开了一篇:机械臂运动学,学完你就能让夹爪精确落到指定坐标,而不是手动试角度。
让动作更稳、更可控:进阶风控与冗余
多舵机、有机械运动的设备,一旦规模化或长时间运行,要考虑的就不只是“能动”了:舵机堵转保护、供电冗余、异常姿态的软件限位、断电保持。这些“让设备在意外情况下也不失控”的思路,属于 机器人专题卷 R 那条更深的线——机械臂正是把这些风控概念落到实处的好载体。等你多做几个动作项目、手感稳了,再顺着 R4 往下啃,把“能抓”做成“怎么抓都不出事”。
做成能天天用的实体
面包板一团线、电源裸接只能算原型。想变成能摆桌上、能演示、甚至能干点真活的东西,要走产品化那条路:稳定供电、走线收纳、给舵机加限位缓冲、外壳固定。这些经验在做过几个项目后自然会想补,机械臂是最值得留着反复打磨的一个。
小结 · 你做出了什么、下一步去哪
- 你做出了一台四到六自由度、能把小物件从 A 抓到 B 的桌面机械臂,从舵机选型、独立供电避雷区接线、分步写 ESP-IDF 码到调试校准,走完了一件多舵机成品的全流程。
- 你把 PCA9685 多舵机驱动(robot-servo-pca9685)和单舵机角度控制(l2-servo)两个知识点,用插值 + 姿态序列组织成了协调的抓取动作——这个“组织多个执行器一起动”的功夫,就是机械臂比“驱动舵机”多出来的那一层。
- 你学到了几个从 demo 到成品的关键思维:把易错的换算封进函数、多关节并行插值而非轮流动、上电先回已知姿态、每个关节都做角度钳位防撞死点、供电永远独立且共地。
下一步:想让它“按坐标抓”而不是手动试角度,去啃 机械臂运动学;想让多舵机设备在意外下也不失控,顺着 机器人专题卷 R 往深走;想系统看这台机械臂和其它机器人项目的关系,去 机器人专题 逛一圈。回看全部实战项目见项目总览。这台机械臂是你所有硬件项目里最有“成就感落差”的一个——从一堆乱动的舵机,到它稳稳夹起第一块橡皮的那一刻,你会明白“组织”二字的分量。
本文为公开资料整理,非亲测。关键参数与代码请结合实物与下列官方来源验证。