ESP32 控制舵机随机旋转

作者:追风剑情 发布于:2026-5-25 16:05 分类:物联网

PWM 的全称是 Pulse Width Modulation,中文翻译为脉冲宽度调制。

原理:舵机是通过控制占空比(duty)来控制旋转角度。

SG90 舵机需要的脉冲宽度范围是 0.5ms 到 2.5ms,这也是绝大多数标准舵机的通用规格。

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "driver/ledc.h"
#include "esp_timer.h"
#include <stdlib.h>
#include <time.h>

// 舵机配置
#define SERVO_GPIO          GPIO_NUM_5   // 信号线接GPIO5
#define SERVO_MIN_PULSE     500          // 最小脉冲宽度 (0度)
#define SERVO_MAX_PULSE     2500         // 最大脉冲宽度 (180度)
#define SERVO_FREQ_HZ       50           // 舵机标准频率 50Hz (周期20ms)

static const char *TAG = "SERVO";

// 初始化舵机 (使用LEDC)
void servo_init(void)
{
    // LEDC定时器配置
    ledc_timer_config_t timer_conf = {
        // 低速模式
        .speed_mode       = LEDC_LOW_SPEED_MODE,
        // 使用0号定时器
        .timer_num        = LEDC_TIMER_0,
        // 14位分辨率 (0-16383)
        .duty_resolution  = LEDC_TIMER_14_BIT,
        // 设置 PWM 的频率
        .freq_hz          = SERVO_FREQ_HZ,
        // 自动选择合适的时钟源
        .clk_cfg          = LEDC_AUTO_CLK
    };
    ledc_timer_config(&timer_conf);
    
    // LEDC通道配置
    ledc_channel_config_t channel_conf = {
        // 信号GPIO引脚
        .gpio_num       = SERVO_GPIO,
        // 低速模式
        .speed_mode     = LEDC_LOW_SPEED_MODE,
        // 使用0号通道
        .channel        = LEDC_CHANNEL_0,
        // 禁用中断
        .intr_type      = LEDC_INTR_DISABLE,
        // 关联0号定时器
        .timer_sel      = LEDC_TIMER_0,
        // 一开始时输出低电平(0V)
        .duty           = 0,
        // 从周期开始时输出高电平
        .hpoint         = 0
    };
    ledc_channel_config(&channel_conf);
    
    ESP_LOGI(TAG, "舵机初始化完成, GPIO: %d", SERVO_GPIO);
}

// 将角度转换为占空比值
// 0度 -> 0.5ms 高电平, 180度 -> 2.5ms 高电平
// 公式: duty = (脉冲宽度_us / 周期_us) * 最大占空比值
int angle_to_duty(int angle)
{
    // 限制角度范围 0-180
    if (angle < 0) angle = 0;
    if (angle > 180) angle = 180;
    
    // 计算对应脉冲宽度 (微秒)
    // 0度: 500us, 180度: 2500us
    int pulse_us = SERVO_MIN_PULSE + (angle * (SERVO_MAX_PULSE - SERVO_MIN_PULSE) / 180);
    
    // 周期 = 1000000us / 50Hz = 20000us
    // 占空比 = 脉冲宽度 / 周期
    // 转换成14位分辨率值: 分辨率值 = 占空比 * 最大分辨率(16383)
    int duty = (pulse_us * 16383) / 20000;
    
    return duty;
}

// 设置舵机角度
void servo_set_angle(int angle)
{
    int duty = angle_to_duty(angle);
    ledc_set_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0, duty);
    ledc_update_duty(LEDC_LOW_SPEED_MODE, LEDC_CHANNEL_0);
    ESP_LOGI(TAG, "舵机转到: %d度", angle);
}

void app_main(void)
{
    // 初始化随机数种子
    srand(time(NULL));
    
    // 初始化舵机
    servo_init();
    
    // 让舵机先转到90度 (中间位置)
    servo_set_angle(90);
    vTaskDelay(1000 / portTICK_PERIOD_MS);
    
    ESP_LOGI(TAG, "开始随机旋转测试...");
    
    while (1) {
        // 生成 0-180 之间的随机角度
        int random_angle = rand() % 181;  // 0到180
        
        // 控制舵机转到随机角度
        servo_set_angle(random_angle);
        
        // 等待1秒
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}


标签: IoT

Powered by emlog  蜀ICP备18021003号-1   sitemap

川公网安备 51019002001593号