STM32驱动SG90舵机实现多关节机械臂控制:从PWM调校到运动协同实战
在创客和机器人爱好者的世界里,能够精准控制的小型机械臂总是充满魅力。想象一下,用几个不足百元的SG90微型舵机,搭配一块STM32开发板,就能搭建出可以抓取物品、绘制简单轨迹的机械臂——这不仅是个有趣的DIY项目,更是理解嵌入式控制系统如何与机械结构互动的绝佳实践。本文将带你从PWM信号的基础调校开始,逐步实现多关节机械臂的协同运动控制。
1. SG90舵机与PWM控制的核心原理
SG90这类微型舵机本质上是一个带有反馈控制的位置伺服系统。它的核心是一个直流电机、减速齿轮组和电位器组成的闭环控制回路。当我们给舵机发送PWM信号时,它内部的控制电路会将脉冲宽度转换为目标角度,并通过比较电位器反馈的实际位置来驱动电机转动,直到到达指定位置。
对于180度范围的SG90舵机,PWM信号的控制规律如下表所示:
| 高电平脉宽(ms) | 对应角度 |
|---|---|
| 0.5 | 0度 |
| 1.0 | 45度 |
| 1.5 | 90度 |
| 2.0 | 135度 |
| 2.5 | 180度 |
在STM32上生成这样的PWM信号,我们需要配置定时器的两个关键参数:
- ARR(Auto-reload register):决定PWM周期
- CCR(Capture/Compare register):决定高电平脉宽
// 初始化定时器3产生50Hz PWM(周期20ms) void PWM_Init(uint16_t arr, uint16_t psc) { TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_TimeBaseStructure.TIM_Period = arr; // ARR值 TIM_TimeBaseStructure.TIM_Prescaler = psc; // 预分频值 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); }2. 多路PWM信号生成与机械臂关节配置
构建一个三自由度机械臂至少需要三个舵机:基座旋转、肘部俯仰和末端夹持。STM32的定时器通常有多个通道,可以同时生成多路PWM信号。以TIM3为例,它支持4个独立通道,足够控制多个关节。
硬件连接建议:
- 每个舵机的信号线连接到不同的定时器通道
- 使用外部5V电源为舵机供电(切勿直接从STM32取电)
- 确保所有GND共地
// 设置TIM3的四个通道输出不同占空比的PWM TIM_SetCompare1(TIM3, 15); // 通道1 - 90度 TIM_SetCompare2(TIM3, 10); // 通道2 - 约60度 TIM_SetCompare3(TIM3, 5); // 通道3 - 0度注意:当多个舵机同时运动时,瞬时电流可能很大,建议在电源端并联大容量电容(如1000μF)稳压。
3. 机械臂运动学基础与关节协同
简单的三自由度机械臂可以看作是由一系列连杆和旋转关节组成的串联结构。要让末端执行器到达特定位置,需要计算各关节的目标角度——这就是逆运动学问题。
以平面二维机械臂为例,设两个关节长度分别为L1和L2,末端位置(x,y)与关节角度θ1、θ2的关系为:
x = L1*cos(θ1) + L2*cos(θ1+θ2) y = L1*sin(θ1) + L2*sin(θ1+θ2)在实际编程中,我们可以预先计算几个关键位置的角度组合:
typedef struct { float theta1; // 关节1角度 float theta2; // 关节2角度 float grip; // 夹持器开合 } ArmPose; const ArmPose home_pose = {90, 90, 0}; const ArmPose pick_pose = {45, 135, 30}; const ArmPose place_pose = {135, 45, 0};4. 运动平滑处理与轨迹规划
直接让舵机从一个角度跳变到另一个角度会导致机械臂动作生硬,甚至可能损坏结构。我们需要实现平滑的过渡:
梯形速度规划算法:
- 加速阶段:角度变化率逐渐增大
- 匀速阶段:保持恒定速度运动
- 减速阶段:角度变化率逐渐减小
void smooth_move(ArmPose start, ArmPose end, uint16_t steps) { for(int i=0; i<=steps; i++) { float ratio = (float)i/steps; ArmPose current; // 线性插值 current.theta1 = start.theta1 + (end.theta1 - start.theta1) * ratio; current.theta2 = start.theta2 + (end.theta2 - start.theta2) * ratio; // 应用角度 set_servo_angle(1, current.theta1); set_servo_angle(2, current.theta2); delay_ms(20); // 控制运动速度 } }5. 机械臂控制系统的进阶优化
当机械臂需要完成更复杂的任务时,可以考虑以下优化方向:
PID位置控制:
- 通过编码器或电位器反馈实际位置
- 计算目标与实际的误差,用PID算法调整PWM输出
typedef struct { float Kp, Ki, Kd; float integral; float prev_error; } PIDController; float pid_update(PIDController* pid, float error, float dt) { pid->integral += error * dt; float derivative = (error - pid->prev_error) / dt; pid->prev_error = error; return pid->Kp*error + pid->Ki*pid->integral + pid->Kd*derivative; }多任务调度:
- 使用RTOS创建独立任务处理各关节控制
- 通过消息队列传递目标位置指令
// FreeRTOS示例任务 void vServoTask(void *pvParameters) { ServoID id = (ServoID)pvParameters; while(1) { float target = xQueueReceive(servo_queues[id], &target, portMAX_DELAY); smooth_move_to(id, target); } }6. 机械结构设计与校准技巧
好的控制算法需要配合合理的机械设计:
机械臂搭建要点:
- 使用轻质材料(如3D打印件、碳纤维杆)减少舵机负载
- 确保各关节转动顺畅,避免过大的摩擦阻力
- 在关键受力点增加加强结构
舵机校准步骤:
- 给所有舵机发送1.5ms脉宽(中间位置)
- 手动安装舵盘,使其处于机械结构的中间位置
- 固定连杆,确保机械臂在零位时姿态正确
- 记录各关节的角度偏移量,在软件中补偿
// 舵机校准参数 const float servo_offsets[] = { -2.5, 3.0, 0.0 }; void set_servo_angle(uint8_t id, float angle) { angle += servo_offsets[id]; // 应用校准偏移 uint16_t pulse = map(angle, 0, 180, 5, 25); // 0.5-2.5ms对应5-25 TIM_SetCompareX(TIM3, id, pulse); // X代表通道号 }7. 典型应用案例:物品分拣机械臂
结合上述技术,我们可以实现一个简单的物品分拣系统:
工作流程:
- 通过颜色传感器识别物品
- 计算抓取位置和放置位置
- 规划无碰撞运动轨迹
- 执行抓取-移动-释放动作序列
关键代码结构:
void pick_and_place(Position pick, Position place) { // 移动到抓取点上方 ArmPose approach = calculate_pose(pick.x, pick.y, 20); // 20mm高度 smooth_move(current_pose, approach, 50); // 下降并抓取 ArmPose grip = calculate_pose(pick.x, pick.y, 0); grip.grip = 80; // 夹持器闭合程度 smooth_move(approach, grip, 30); // 抬起并移动到放置点 ArmPose carry = grip; carry.theta1 = approach.theta1; carry.theta2 = approach.theta2; smooth_move(grip, carry, 30); // 放置物品 ArmPose release = calculate_pose(place.x, place.y, 0); release.grip = 0; smooth_move(carry, release, 50); }在调试这类项目时,最耗时的往往不是代码本身,而是机械结构的微调和运动参数的优化。建议准备一套小螺丝刀、垫片和热熔胶枪,随时调整机械部件的配合间隙。对于运动控制,可以先单独调试每个关节的运动范围,再逐步组合成复合动作。