智能小车避障、云台跟踪?从SG90舵机控制开始玩转STM32 HAL库PWM
从SG90舵机到智能避障小车:STM32 HAL库PWM实战指南
当第一次看到SG90舵机在智能小车上灵活转向时,那种机械结构精准响应代码指令的奇妙感,让我彻底迷上了嵌入式开发。这个重量仅9克的小型舵机,却能承载1.5kg·cm的扭矩,成为无数创客项目中的核心执行器。本文将带你超越基础的角度控制,探索如何将SG90融入真实的智能硬件系统——无论是自动避障的小车、追踪目标的云台,还是简易机械臂,关键在于掌握PWM的精髓与多模块协同的艺术。
1. SG90舵机深度解析与HAL库PWM配置
1.1 舵机内部构造与PWM控制原理
撕开SG90的塑料外壳,你会发现它由三个关键部件组成:小型直流电机、减速齿轮组和位置反馈电位器。当PWM信号输入时,控制电路会比较电位器反馈的当前位置与目标位置,驱动电机正转或反转直到两者匹配。这种闭环控制机制使得舵机能够精确保持角度,即使受到外力干扰。
对于180度版本的SG90,其PWM控制规律可总结为:
| 脉冲宽度(ms) | 对应角度 | 占空比(50Hz) | 计数器值(ARR=1999) |
|---|---|---|---|
| 0.5 | 0° | 2.5% | 50 |
| 1.0 | 45° | 5.0% | 100 |
| 1.5 | 90° | 7.5% | 150 |
| 2.0 | 135° | 10.0% | 200 |
| 2.5 | 180° | 12.5% | 250 |
提示:实际项目中建议将角度-脉冲宽度关系封装为函数,避免每次手动计算:
uint16_t angle_to_compare(uint8_t angle) { return (uint16_t)(50 + (angle / 180.0) * 200); }
1.2 CubeMX定时器配置实战
在STM32CubeMX中配置TIM3生成50Hz PWM的步骤如下:
- 时钟树配置:确保APB1定时器时钟为72MHz(STM32F103系列)
- 定时器参数设置:
- Prescaler (PSC): 719
- Counter Period (ARR): 1999
- 计算验证:72MHz / (719+1) / (1999+1) = 50Hz
- PWM通道启用:选择对应通道的PWM Generation模式
- GPIO分配:自动配置为复用推挽输出,无需额外设置
// 生成的初始化代码片段 TIM_HandleTypeDef htim3; TIM_OC_InitTypeDef sConfigOC = {0}; htim3.Instance = TIM3; htim3.Init.Prescaler = 719; htim3.Init.CounterMode = TIM_COUNTERMODE_UP; htim3.Init.Period = 1999; HAL_TIM_PWM_Init(&htim3); sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = 0; // 初始占空比 sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);2. 智能小车转向系统集成
2.1 机械结构与舵机安装
将SG90作为智能小车的前轮转向机构时,需要注意:
- 扭矩匹配:SG90在4.8V电压下扭矩为1.5kg·cm,需确保转向机构阻力矩不超过此值
- 机械联动:建议使用3D打印的转向连杆机构,减少虚位
- 供电隔离:舵机与主控板使用独立电源或大容量电容滤波,避免电机启动造成电压骤降
典型连接方案:
[锂电池] → [5V稳压模块] → 舵机VCC ↘ [3.3V稳压] → STM322.2 多任务控制框架
避免在main循环中使用HAL_Delay()阻塞系统,推荐采用定时器中断实现非阻塞控制:
// 在定时器中断回调中更新舵机角度 void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if(htim == &htim4) { // 假设TIM4用于10ms周期任务 static uint32_t tick = 0; if(++tick % 10 == 0) { // 每100ms更新一次 uint16_t target_angle = get_target_angle(); // 从传感器获取目标角度 __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, angle_to_compare(target_angle)); } } }3. 超声波避障与舵机联动
3.1 硬件连接方案
典型的HC-SR04超声波模块与STM32连接方式:
Trig -- PA1 (GPIO输出) Echo -- PA2 (GPIO输入) SG90 -- PA6 (TIM3_CH1 PWM输出)3.2 避障算法实现
采用简单的扫描-决策模式:
- 扫描阶段:舵机按预设角度步进扫描(如0°→45°→90°→135°→180°)
- 测距采样:在每个角度停留200ms,采集5次超声波数据取中值
- 决策逻辑:
- 找出最远距离的方向
- 若所有方向距离<15cm,执行倒车流程
typedef struct { uint8_t angle; uint16_t distance; } ScanPoint; void obstacle_avoidance() { ScanPoint scan_points[5]; const uint8_t angles[] = {0, 45, 90, 135, 180}; // 扫描环境 for(int i=0; i<5; i++) { set_servo_angle(angles[i]); HAL_Delay(200); // 等待舵机稳定 scan_points[i] = (ScanPoint){ .angle = angles[i], .distance = ultrasonic_measure() }; } // 寻找最优路径 uint8_t best_angle = 90; // 默认直行 uint16_t max_dist = 0; for(int i=0; i<5; i++) { if(scan_points[i].distance > max_dist) { max_dist = scan_points[i].distance; best_angle = scan_points[i].angle; } } // 执行转向 if(max_dist < 15) { emergency_stop(); } else { smooth_turn(best_angle); // 带缓动的转向函数 } }4. 视觉追踪云台开发
4.1 OpenMV与STM32通信
通过串口实现视觉处理器与STM32的指令传输:
OpenMV TX -- STM32 RX (PA10) OpenMV RX -- STM32 TX (PA9) GND共地数据协议建议采用简单的文本格式:
"X123Y45\n" 表示目标在图像坐标系中的坐标(123,45)4.2 双舵机云台控制
对于需要俯仰(Pitch)和偏航(Yaw)双自由度的云台:
// 云台控制结构体 typedef struct { TIM_HandleTypeDef *pitch_tim; uint32_t pitch_ch; TIM_HandleTypeDef *yaw_tim; uint32_t yaw_ch; } GimbalController; void gimbal_track_target(GimbalController *gimbal, int16_t x_err, int16_t y_err) { // 简单的比例控制 static int16_t pitch_angle = 90, yaw_angle = 90; // 更新角度 (Kp=0.1) yaw_angle += x_err * 0.1; pitch_angle -= y_err * 0.1; // 限制角度范围 pitch_angle = constrain(pitch_angle, 60, 120); yaw_angle = constrain(yaw_angle, 30, 150); // 设置PWM __HAL_TIM_SET_COMPARE(gimbal->yaw_tim, gimbal->yaw_ch, angle_to_compare(yaw_angle)); __HAL_TIM_SET_COMPARE(gimbal->pitch_tim, gimbal->pitch_ch, angle_to_compare(pitch_angle)); }4.3 常见问题解决方案
问题1:舵机抖动
- 检查电源电压是否稳定(建议使用示波器观察)
- 在PWM信号线增加100nF电容滤波
- 确保机械结构没有过大的阻力
问题2:角度控制不精确
- 校准舵机零点(有些SG90需要0.5ms~2.5ms以外的脉冲)
- 使用更高精度的定时器(如32位定时器)
- 考虑使用数字舵机替代模拟舵机
问题3:多舵机协同问题
- 为每个舵机分配独立的定时器通道
- 避免同时更新多个舵机角度,可错时处理
- 使用PCA9685等专用PWM驱动芯片扩展控制能力
在最近的一个自动喂食器项目中,我发现SG90在长时间工作后会出现约3°的偏差积累。通过增加光电开关作为归零传感器,配合每周一次的自动校准流程,成功将长期精度控制在±1°以内。这种实战中的小技巧往往比理论参数更有价值。
