esp32 idf控制舵机MG90s

esp32 idf控制舵机MG90s

黄色:信号

红色:VCC

棕色:GND

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/ledc.h"
#include "esp_err.h"


#define SERVO_PIN    18          // 舵机信号引脚
#define LEDC_TIMER   LEDC_TIMER_0
#define LEDC_MODE    LEDC_LOW_SPEED_MODE
#define LEDC_CHANNEL LEDC_CHANNEL_0
#define LEDC_DUTY_RES LEDC_TIMER_14_BIT  // 分辨率:2^14 = 16384
#define LEDC_FREQ_HZ 50                  // 50Hz (20ms 周期)

// 将角度(0~180)转换为 duty 值
uint32_t angle_to_duty(uint8_t angle) {
    // 脉宽范围:500us ~ 2500us 对应 0~180°
    // 周期 = 1 / 50Hz = 20,000 us
    // duty = (pulse_width_us / 20000.0) * (2^14)
    float pulse_width_us = 500 + (angle * 2000.0 / 180.0); // 线性映射
    return (uint32_t)((pulse_width_us / 20000.0) * (1 << LEDC_DUTY_RES));
}

void app_main(void)
{
    // 配置 LEDC 定时器
    ledc_timer_config_t timer_conf = {
        .speed_mode = LEDC_MODE,
        .timer_num  = LEDC_TIMER,
        .duty_resolution = LEDC_DUTY_RES,
        .freq_hz    = LEDC_FREQ_HZ,
        .clk_cfg    = LEDC_AUTO_CLK,
    };
    ESP_ERROR_CHECK(ledc_timer_config(&timer_conf));

    // 配置 LEDC 通道
    ledc_channel_config_t channel_conf = {
        .gpio_num   = SERVO_PIN,
        .speed_mode = LEDC_MODE,
        .channel    = LEDC_CHANNEL,
        .timer_sel  = LEDC_TIMER,
        .duty       = 0, // 初始为 0
        .hpoint     = 0,
    };
    ESP_ERROR_CHECK(ledc_channel_config(&channel_conf));

    // 测试:让舵机从 0° 转到 180°,再返回
    while (1) {
        for (int angle = 0; angle <= 180; angle += 50) {
            uint32_t duty = angle_to_duty(angle);
            ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
            ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
            printf("Angle: %d°, Duty: %lu\n", angle, duty);
            vTaskDelay(pdMS_TO_TICKS(1000)); // 每步停 0.5 秒
        }
        for (int angle = 170; angle >= 0; angle -= 50) {
            uint32_t duty = angle_to_duty(angle);
            ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty));
            ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
            printf("Angle: %d°, Duty: %lu\n", angle, duty);
            vTaskDelay(pdMS_TO_TICKS(1000));
        }
    }
}

 同时控制两个舵机:

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/ledc.h"
#include "esp_err.h"

// 舵机配置
#define SERVO_PIN_1    18          // 第一个舵机引脚
#define SERVO_PIN_2    19          // 第二个舵机引脚

#define LEDC_TIMER     LEDC_TIMER_0
#define LEDC_MODE      LEDC_LOW_SPEED_MODE
#define LEDC_DUTY_RES  LEDC_TIMER_14_BIT  // 分辨率:2^14 = 16384
#define LEDC_FREQ_HZ   50                 // 50Hz (20ms 周期)

// 将角度(0~180)转换为 duty 值
uint32_t angle_to_duty(uint8_t angle) {
    float pulse_width_us = 500 + (angle * 2000.0f / 180.0f); // 500~2500us
    return (uint32_t)((pulse_width_us / 20000.0f) * (1 << LEDC_DUTY_RES));
}

void app_main(void)
{
    // 配置 LEDC 定时器(两个舵机共用)
    ledc_timer_config_t timer_conf = {
        .speed_mode       = LEDC_MODE,
        .timer_num        = LEDC_TIMER,
        .duty_resolution  = LEDC_DUTY_RES,
        .freq_hz          = LEDC_FREQ_HZ,
        .clk_cfg          = LEDC_AUTO_CLK,
    };
    ESP_ERROR_CHECK(ledc_timer_config(&timer_conf));

    // 配置第一个舵机通道(GPIO 18)
    ledc_channel_config_t channel_conf_1 = {
        .gpio_num   = SERVO_PIN_1,
        .speed_mode = LEDC_MODE,
        .channel    = LEDC_CHANNEL_0,   // 通道0
        .timer_sel  = LEDC_TIMER,
        .duty       = 0,
        .hpoint     = 0,
    };
    ESP_ERROR_CHECK(ledc_channel_config(&channel_conf_1));

    // 配置第二个舵机通道(GPIO 19)
    ledc_channel_config_t channel_conf_2 = {
        .gpio_num   = SERVO_PIN_2,
        .speed_mode = LEDC_MODE,
        .channel    = LEDC_CHANNEL_1,   // 通道1
        .timer_sel  = LEDC_TIMER,
        .duty       = 0,
        .hpoint     = 0,
    };
    ESP_ERROR_CHECK(ledc_channel_config(&channel_conf_2));

    // 测试:让两个舵机独立运动
    while (1) {
        // 正向:0° → 180°
        for (int angle = 0; angle <= 180; angle += 30) {
            uint32_t duty1 = angle_to_duty(angle);
            uint32_t duty2 = angle_to_duty(180 - angle); // 反向运动

            ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_0, duty1));
            ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_0));

            ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_1, duty2));
            ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_1));

            printf("Servo1: %d°, Servo2: %d°\n", angle, 180 - angle);
            vTaskDelay(pdMS_TO_TICKS(500)); // 每步停 0.5 秒
        }

        // 反向:180° → 0°
        for (int angle = 180; angle >= 0; angle -= 30) {
            uint32_t duty1 = angle_to_duty(angle);
            uint32_t duty2 = angle_to_duty(180 - angle);

            ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_0, duty1));
            ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_0));

            ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL_1, duty2));
            ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL_1));

            printf("Servo1: %d°, Servo2: %d°\n", angle, 180 - angle);
            vTaskDelay(pdMS_TO_TICKS(500));
        }
    }
}

 

posted @ 2026-01-03 13:58  txwtech  阅读(17)  评论(0)    收藏  举报