news 2026/4/23 17:16:17

STM32驱动SG90舵机做个小机械臂:从PWM原理到多关节协同控制实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32驱动SG90舵机做个小机械臂:从PWM原理到多关节协同控制实战

STM32驱动SG90舵机实现多关节机械臂控制:从PWM调校到运动协同实战

在创客和机器人爱好者的世界里,能够精准控制的小型机械臂总是充满魅力。想象一下,用几个不足百元的SG90微型舵机,搭配一块STM32开发板,就能搭建出可以抓取物品、绘制简单轨迹的机械臂——这不仅是个有趣的DIY项目,更是理解嵌入式控制系统如何与机械结构互动的绝佳实践。本文将带你从PWM信号的基础调校开始,逐步实现多关节机械臂的协同运动控制。

1. SG90舵机与PWM控制的核心原理

SG90这类微型舵机本质上是一个带有反馈控制的位置伺服系统。它的核心是一个直流电机、减速齿轮组和电位器组成的闭环控制回路。当我们给舵机发送PWM信号时,它内部的控制电路会将脉冲宽度转换为目标角度,并通过比较电位器反馈的实际位置来驱动电机转动,直到到达指定位置。

对于180度范围的SG90舵机,PWM信号的控制规律如下表所示:

高电平脉宽(ms)对应角度
0.50度
1.045度
1.590度
2.0135度
2.5180度

在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. 运动平滑处理与轨迹规划

直接让舵机从一个角度跳变到另一个角度会导致机械臂动作生硬,甚至可能损坏结构。我们需要实现平滑的过渡:

梯形速度规划算法

  1. 加速阶段:角度变化率逐渐增大
  2. 匀速阶段:保持恒定速度运动
  3. 减速阶段:角度变化率逐渐减小
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. 给所有舵机发送1.5ms脉宽(中间位置)
  2. 手动安装舵盘,使其处于机械结构的中间位置
  3. 固定连杆,确保机械臂在零位时姿态正确
  4. 记录各关节的角度偏移量,在软件中补偿
// 舵机校准参数 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. 典型应用案例:物品分拣机械臂

结合上述技术,我们可以实现一个简单的物品分拣系统:

工作流程

  1. 通过颜色传感器识别物品
  2. 计算抓取位置和放置位置
  3. 规划无碰撞运动轨迹
  4. 执行抓取-移动-释放动作序列

关键代码结构

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); }

在调试这类项目时,最耗时的往往不是代码本身,而是机械结构的微调和运动参数的优化。建议准备一套小螺丝刀、垫片和热熔胶枪,随时调整机械部件的配合间隙。对于运动控制,可以先单独调试每个关节的运动范围,再逐步组合成复合动作。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 17:15:30

智能电表抄表协议DL/T645和698.45,手把手教你用Python解析报文(附代码)

智能电表通信协议解析实战&#xff1a;从DL/T645报文到Python实现 在工业物联网和智能电网快速发展的今天&#xff0c;电力数据的精准采集与分析变得尤为重要。作为连接智能电表与数据采集系统的桥梁&#xff0c;DL/T645和DL/T698.45协议扮演着关键角色。对于开发者而言&#x…

作者头像 李华
网站建设 2026/4/23 17:15:28

立达信:海外产能叠加鸿蒙生态赋能 智能照明龙头再获市场聚焦

近期&#xff0c;光学光电子板块整体表现活跃&#xff0c;市场资金对细分领域龙头企业的关注度明显升温。其中&#xff0c;LED照明出口龙头立达信&#xff08;605365.SH&#xff09;凭借海外产能布局与鸿蒙生态合作等多重催化因素&#xff0c;成为板块中市场关注度较高的个股之…

作者头像 李华
网站建设 2026/4/23 17:15:20

《每日一命令08:scp——安全的远程复制》

先唠两句大家好啊&#xff0c;我是阿垚。欢迎来到《每日一命令》第08期。上期聊了ssh——远程登录神器。今天聊一个基于ssh的文件传输工具&#xff1a;scp你是不是还在用rsync&#xff1f;或者用rz/sz&#xff1f;其实scp是最简单、最直接的远程文件复制命令。(&#xff61;•ᴗ…

作者头像 李华
网站建设 2026/4/23 17:15:01

别再死记硬背for循环语法了!用C#实战打印九九乘法表,5分钟彻底搞懂

用C#实战打印九九乘法表&#xff1a;5分钟彻底搞懂for循环精髓 记得第一次面试时&#xff0c;面试官让我手写一个九九乘法表。我脑子里瞬间闪过各种语法规则&#xff0c;却不知从何下手。直到后来才发现&#xff0c;理解for循环最好的方式不是背诵语法&#xff0c;而是动手实现…

作者头像 李华
网站建设 2026/4/23 17:13:20

OLMo 1B模型指令微调实战指南

1. 指令微调基础与OLMo 1B模型解析指令微调&#xff08;Instruction Tuning&#xff09;是当前大语言模型&#xff08;LLM&#xff09;领域的关键技术之一。简单来说&#xff0c;它就像给一个天赋异禀但缺乏专业训练的学生进行针对性辅导——基础模型已经具备强大的语言理解和生…

作者头像 李华