从零搭建写字机器人:基于ESP32与PCA9685的机械臂控制实战

张开发
2026/4/7 12:42:41 15 分钟阅读

分享文章

从零搭建写字机器人:基于ESP32与PCA9685的机械臂控制实战
1. 项目概述写字机器人能做什么想象一下当你用笔在纸上写下自己的名字时手臂的肌肉是如何协同工作的。现在我们要用三个舵机来模拟这个过程让机械臂像人类手臂一样流畅书写。这个项目最有趣的地方在于它完美结合了数学计算、硬件控制和编程技巧。我最初尝试这个项目时被坐标转换的数学问题困扰了很久。后来发现其实只要掌握几个关键点就能让机械臂乖乖听话。这个写字机器人虽然结构简单但已经包含了工业机械臂的核心原理。你可以用它来练习签名、绘制简单图形甚至作为教学演示工具。2. 硬件准备与连接2.1 核心元件清单你需要准备以下硬件组件ESP32开发板推荐使用NodeMCU-32S性价比高且引脚标识清晰PCA9685舵机驱动模块16通道可同时控制多个舵机MG996R舵机3个金属齿轮扭矩足够且价格适中杜邦线若干建议使用20cm长度的公对公线5V/3A电源适配器单独给舵机供电更稳定亚克力机械臂套件或3D打印的机械结构我在第一次搭建时用了便宜的SG90舵机结果发现扭矩太小根本抬不动笔。后来换成MG996R就稳定多了建议不要在这上面省钱。电源也要特别注意ESP32和舵机最好分开供电避免电流过大导致开发板重启。2.2 硬件连接图解具体接线方式如下将ESP32的GPIO21接PCA9685的SDA将ESP32的GPIO22接PCA9685的SCLPCA9685的VCC接5V电源正极PCA9685的GND与ESP32共地三个舵机信号线分别接PCA9685的0、1、2通道舵机电源统一接5V电源不要从ESP32取电这里有个容易踩坑的地方I2C地址冲突。PCA9685默认地址是0x40如果同时连接其他I2C设备可能需要调整模块背面的地址跳线。我第一次调试时因为OLED屏幕也用了I2C导致舵机完全没反应排查了好久才发现这个问题。3. 核心算法解析3.1 坐标到角度的转换机械臂的运动学计算是这个项目最烧脑的部分。我们需要把二维平面坐标(x,y)转换为两个舵机的旋转角度。这涉及到逆向运动学计算具体公式推导如下import math class Kinematics: def __init__(self, arm_length50): self.upper_arm arm_length # 大臂长度 self.forearm arm_length # 小臂长度 def calculate_angles(self, x, y): # 计算末端到原点的距离 distance math.sqrt(x**2 y**2) # 检查是否在可达范围内 if distance (self.upper_arm self.forearm): raise ValueError(目标位置超出机械臂工作范围) # 计算大臂角度相对于X轴 alpha math.atan2(y, x) - math.acos( (self.upper_arm**2 distance**2 - self.forearm**2) / (2 * self.upper_arm * distance)) # 计算小臂角度相对于大臂 beta math.pi - math.acos( (self.upper_arm**2 self.forearm**2 - distance**2) / (2 * self.upper_arm * self.forearm)) return math.degrees(alpha), math.degrees(beta)实际测试中发现当机械臂接近工作边界时会出现奇异点问题导致角度计算不稳定。我的解决办法是限制工作范围确保x坐标始终大于10cm。另外三角函数计算要考虑象限问题使用atan2比atan更可靠。3.2 角度到PWM的转换每个舵机的PWM参数都需要单独校准这是最耗时的环节。我总结了一套校准方法准备量角器和直尺将舵机置于中间位置90度记录此时的PWM值分别转到0度和180度记录对应的PWM值计算线性系数k (max_pwm - min_pwm)/180class ServoCalibration: def __init__(self): # 实测的三个舵机参数 [抬笔舵机, 大臂舵机, 小臂舵机] self.init_pwm [330, 185, 390] # 中间位置PWM值 self.k_values [2.28, 2.00, 1.78] # 每度对应的PWM变化量 def angle_to_pwm(self, servo_id, angle): 将角度转换为PWM信号 return int(self.init_pwm[servo_id] angle * self.k_values[servo_id])特别注意小臂舵机在我的机械结构上是反向安装的所以实际代码中要对角度取反。不同品牌的舵机PWM特性可能差异很大建议购买同一批次的舵机以减少校准工作量。4. 软件实现详解4.1 绘图坐标采集使用Python的turtle模块可以方便地获取绘图路径。我改进了原始方案增加了动态分段功能import turtle class PathRecorder: def __init__(self, segment_length5): self.pen turtle.Pen() self.segment_length segment_length self.positions [] def record_move(self, distance): steps max(3, int(distance / self.segment_length)) for _ in range(steps): self.positions.append(self.pen.pos()) self.pen.forward(distance/steps) def save_path(self, filename): with open(filename, w) as f: f.write(str(self.positions)) # 示例绘制五角星并记录路径 recorder PathRecorder() for _ in range(5): recorder.record_move(100) recorder.pen.right(144) recorder.save_path(star_path.txt)这个改进版会根据移动距离自动调整采样点密度避免短线段采样不足或长线段采样过多的问题。实际测试发现对于曲线路径建议将segment_length设置为3-5mm可以获得平滑的运动轨迹。4.2 ESP32主控程序MicroPython代码主要负责三件事读取坐标数据、执行运动学计算、控制PWM输出。下面是核心逻辑from machine import Pin, I2C import time import math class DrawingRobot: def __init__(self): self.i2c I2C(sdaPin(21), sclPin(22)) self.pca PCA9685(self.i2c) self.pca.freq(50) # 舵机标准频率 # 机械臂参数 self.arm_length 50 # mm self.servo_cal ServoCalibration() def move_to(self, x, y): try: # 坐标转换 alpha, beta self.calculate_angles(x, y) # PWM输出 self.pca.duty(1, self.servo_cal.angle_to_pwm(1, alpha)) self.pca.duty(2, self.servo_cal.angle_to_pwm(2, beta)) time.sleep_ms(50) # 运动间隔 except ValueError as e: print(f移动失败: {e}) def pen_control(self, downTrue): pwm self.servo_cal.init_pwm[0] if down: self.pca.duty(0, pwm - 50) else: self.pca.duty(0, pwm 50) time.sleep_ms(200) # 使用示例 robot DrawingRobot() robot.pen_control(False) # 抬笔 robot.move_to(70, 30) # 移动到起始位置 robot.pen_control(True) # 落笔实际部署时发现直接发送目标PWM会导致舵机抖动。后来增加了平滑移动算法将大距离移动分解为多段小距离移动效果明显改善。另一个优化点是加入了异常处理当坐标超出工作范围时会立即停止并提示错误。5. 调试技巧与优化建议5.1 常见问题排查在项目开发过程中我遇到了几个典型问题舵机抖动或不响应检查电源是否足够建议用万用表测量电压确保所有GND共地。PCA9685的OE引脚要接GND使能输出。机械臂运动不准确先用示波器检查PWM信号是否正确。然后单独测试每个舵机确认机械结构没有卡顿。我的一个舵机齿轮有轻微磨损导致回中位置不准。I2C通信失败尝试降低I2C频率我最后用10kHz才稳定。检查线长不要超过20cm必要时加上拉电阻4.7kΩ。5.2 性能优化方向经过多次迭代我发现这几个优化最有效运动轨迹预测提前计算整条路径的PWM值使用环形缓冲区存储避免实时计算带来的延迟。速度控制根据移动距离动态调整运动间隔时间长距离移动加快速度短距离移动放慢速度。笔压调节增加压力传感器或使用弹簧结构保持笔尖与纸面的接触力度一致。校准工具开发图形界面校准程序通过滑块实时调整舵机参数并保存配置。这个项目最让我惊喜的是用如此简单的结构就能实现基本的书写功能。虽然精度不如商业产品但学习价值非常高。建议先用铅笔调试避免墨水弄脏工作台。当第一次看到机械臂写出自己的名字时那种成就感绝对值得所有投入的时间。

更多文章