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)); } } }
欢迎讨论,相互学习。
cdtxw@foxmail.com

浙公网安备 33010602011771号