diff --git a/docs/docs/guide/.obsidian/appearance.json b/docs/docs/guide/.obsidian/appearance.json index 01397d3..3e9db9e 100644 --- a/docs/docs/guide/.obsidian/appearance.json +++ b/docs/docs/guide/.obsidian/appearance.json @@ -4,5 +4,7 @@ "page-width" ], "cssTheme": "GitHub Theme", - "accentColor": "#37b94d" + "accentColor": "#37b94d", + "baseFontSizeAction": true, + "baseFontSize": 20 } \ No newline at end of file diff --git a/docs/docs/guide/.obsidian/workspace.json b/docs/docs/guide/.obsidian/workspace.json index 3bd9cdf..26f384d 100644 --- a/docs/docs/guide/.obsidian/workspace.json +++ b/docs/docs/guide/.obsidian/workspace.json @@ -13,13 +13,13 @@ "state": { "type": "markdown", "state": { - "file": "10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/28BYJ-48步进电机.md", + "file": "10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/SG90舵机.md", "mode": "source", "source": false, "backlinks": false }, "icon": "lucide-file", - "title": "28BYJ-48步进电机" + "title": "SG90舵机" } } ] @@ -85,13 +85,13 @@ "state": { "type": "outline", "state": { - "file": "10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/28BYJ-48步进电机.md", + "file": "10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/SG90舵机.md", "followCursor": false, "showSearch": false, "searchQuery": "" }, "icon": "lucide-list", - "title": "28BYJ-48步进电机 的大纲" + "title": "SG90舵机 的大纲" } } ] @@ -109,8 +109,12 @@ }, "active": "ba89e06e4ba5dcbd", "lastOpenFiles": [ - "10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/SG90舵机.md", "10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/28BYJ-48步进电机.md", + "04.外设学习/4.1-基础外设/4.1.6-LED_PWM/LED_PWM控制.md", + "10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/SG90舵机.md", + "10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments/Pasted image 20250528152414.png", + "10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments/Pasted image 20250528152307.png", + "10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments", "10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/attachments/Pasted image 20250527165130.png", "10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/attachments/Pasted image 20250527163637.png", "10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/attachments/Pasted image 20250527163522.png", @@ -118,7 +122,6 @@ "10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/attachments/Pasted image 20250527161829.png", "10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/attachments", "目录.md", - "04.外设学习/4.1-基础外设/4.1.6-LED_PWM/LED_PWM控制.md", "04.外设学习/4.1-基础外设/4.1.1-GPIO/GPIO入门.md", "attachments/Templates.md", "04.外设学习/4.1-基础外设/4.1.4-ADC/ADC模数转换.md", @@ -134,7 +137,6 @@ "attachments/20250202192226.png", "01.认识ESP32/1.2-ESP32开发环境搭建/1.环境搭建-Windows.md", "03.FreeRTOS基础/3.4-FreeRTOS软件定时器/FreeRTOS软件定时器.md", - "00.常见问题及解决方案/attachments/20250506154522.png", - "00.常见问题及解决方案/attachments/Pasted image 20250506154437.png" + "00.常见问题及解决方案/attachments/20250506154522.png" ] } \ No newline at end of file diff --git a/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/28BYJ-48步进电机.md b/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/28BYJ-48步进电机.md index 56551ce..c888f14 100644 --- a/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/28BYJ-48步进电机.md +++ b/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.1-28BYJ-48步进电机/28BYJ-48步进电机.md @@ -4,8 +4,8 @@ > [!TIP] 🚀 ESP32 模块驱动案例 | 轻松驱动28BYJ-48步进电机 > - 💡 **碎碎念**😎:本节将介绍ESP-IDF环境下驱动28BYJ-48步进电机的原理和相关代码编写。 > - 📺 **视频教程**:🚧 *开发中* -> - 💾 **示例代码**:🚧 *开发中* -> +> - 💾 **示例代码**:[ESP32-Guide/code/10.practice/common_modules/28byj-48](https://github.com/DuRuofu/ESP32-Guide/tree/main/code/10.practice/common_modules/28byj-48) + ## 一、介绍 @@ -20,10 +20,7 @@ 28BYJ-48 可以使用以下驱动方式: -单四相(Wave Drive):每次只激活一个线圈,最低功耗,但扭矩最小 - - - +- 单四相(Wave Drive):每次只激活一个线圈,最低功耗,但扭矩最小 - 双四相(Full Step):每次激活两个线圈,扭矩较大 - 八拍细分(Half Step):交替激活单个和两个线圈,运动最平稳,精度最高(推荐) @@ -64,6 +61,8 @@ ULN2003是一种新型的七路高耐压、大电流达林顿晶体管驱动IC ## 三、示例 +下面的代码实现一个简单的八拍细分的控制逻辑: + ```c #include #include "freertos/FreeRTOS.h" diff --git a/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/SG90舵机.md b/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/SG90舵机.md index 320e7ea..d08ded2 100644 --- a/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/SG90舵机.md +++ b/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/SG90舵机.md @@ -3,29 +3,136 @@ > [!TIP] 🚀 ESP32 模块驱动案例 | 驱动SG90舵机 > - 💡 **碎碎念**😎:本节将介绍使用ESP32驱动SG90舵机 > - 📺 **视频教程**:🚧 *开发中* -> - 💾 **示例代码**:🚧 *开发中* +> - 💾 **示例代码**:[ESP32-Guide/code/10.practice/common_modules/sg90](https://github.com/DuRuofu/ESP32-Guide/tree/main/code/10.practice/common_modules/sg90) > ## 一、介绍 ### 1.1 SG90 舵机简介 +SG90 是一种常见的小型舵机,重量轻、体积小、性价比高,广泛应用于遥控模型、机器人、智能车、机械臂等项目中。其内部包含一个小型电机、齿轮减速系统、位置反馈电位器以及控制电路。SG90 通常具有 180° 的旋转范围(部分版本可能限制在 0~120°),通过控制输入的 PWM 信号即可实现精确的角度控制。 + +![](attachments/Pasted%20image%2020250528152307.png) + +其引脚定义如下: + +![](attachments/Pasted%20image%2020250528152414.png) + +红色:VCC / 棕色:GND / 橙色:信号线 ### 1.2 PWM 控制原理 +SG90 是通过 PWM(Pulse Width Modulation,脉宽调制)信号来控制的。PWM 信号的周期通常为 20ms(即 50Hz 频率),其中关键的是“高电平脉宽”,也称为占空时间。这个脉宽决定了舵机转动的角度。 +- 控制信号为周期性方波,周期固定为 20ms; +- 高电平时间(脉宽)通常在 0.5ms ~ 2.5ms 之间; +- 舵机会根据该脉宽转动到相应角度的位置; +- 舵机会持续对该信号进行采样,保持在设定角度上。 ### 1.3 舵机角度与脉宽关系 +SG90 舵机的角度和 PWM 脉宽呈线性关系。典型的对应关系如下: +| 脉宽(ms) | 对应角度(°) | +| ------ | -------- | +| 0.5 ms | 0°(最左) | +| 1.0 ms | 45° | +| 1.5 ms | 90°(中位) | +| 2.0 ms | 135° | +| 2.5 ms | 180°(最右) | ## 二、使用 +驱动 SG90 舵机通常使用 PWM 信号,而 ESP32 提供了灵活的 LEDC(LED Control)外设,可以非常方便地输出稳定的 PWM 信号,适合控制舵机这类需要特定周期和脉宽的外设。 +LEDC 外设支持以下功能: + +- 高精度定时(可配置频率和占空比) +- 多通道支持 +- 高速与低速模式 + +对于 SG90 舵机,建议配置: + +- PWM 频率:50Hz(周期 20ms) +- 占空比范围:对应脉宽为 0.5ms ~ 2.5ms,占整个周期的 2.5% ~ 12.5% ## 三、示例 +```c +#include +#include "driver/ledc.h" +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_err.h" +#define LEDC_TIMER LEDC_TIMER_0 +#define LEDC_MODE LEDC_LOW_SPEED_MODE +#define LEDC_OUTPUT_IO (2) // 控制舵机的GPIO口 +#define LEDC_CHANNEL LEDC_CHANNEL_0 +#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // 13位分辨率 -> 8192 +#define LEDC_FREQUENCY (50) // 舵机需要 50Hz 周期 (20ms) + +// 占空比计算: +// 13位分辨率,满周期 = 8192(即 100%) +// 对应脉宽范围 0.5ms ~ 2.5ms -> 占周期的 2.5% ~ 12.5% +#define SERVO_MIN_DUTY_US 500 // 0.5ms +#define SERVO_MAX_DUTY_US 2500 // 2.5ms +#define SERVO_PERIOD_US 20000 // 20ms = 50Hz + +static void ledc_init(void) +{ + ledc_timer_config_t ledc_timer = { + .speed_mode = LEDC_MODE, + .duty_resolution = LEDC_DUTY_RES, + .timer_num = LEDC_TIMER, + .freq_hz = LEDC_FREQUENCY, + .clk_cfg = LEDC_AUTO_CLK}; + ESP_ERROR_CHECK(ledc_timer_config(&ledc_timer)); + + ledc_channel_config_t ledc_channel = { + .speed_mode = LEDC_MODE, + .channel = LEDC_CHANNEL, + .timer_sel = LEDC_TIMER, + .intr_type = LEDC_INTR_DISABLE, + .gpio_num = LEDC_OUTPUT_IO, + .duty = 0, + .hpoint = 0}; + ESP_ERROR_CHECK(ledc_channel_config(&ledc_channel)); +} + +// 设置舵机角度(0~180) +void set_servo_angle(uint8_t angle) +{ + if (angle > 180) + angle = 180; + + uint32_t pulse_width_us = SERVO_MIN_DUTY_US + + ((SERVO_MAX_DUTY_US - SERVO_MIN_DUTY_US) * angle) / 180; + + uint32_t duty = (pulse_width_us * (1 << LEDC_DUTY_RES)) / SERVO_PERIOD_US; + + ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, duty); + ledc_update_duty(LEDC_MODE, LEDC_CHANNEL); +} + +void app_main(void) +{ + ledc_init(); + + // 依次转动 0° → 90° → 180° + set_servo_angle(0); + vTaskDelay(pdMS_TO_TICKS(1000)); + + set_servo_angle(90); + vTaskDelay(pdMS_TO_TICKS(1000)); + + set_servo_angle(180); + vTaskDelay(pdMS_TO_TICKS(1000)); + while (1) + { + vTaskDelay(pdMS_TO_TICKS(1000)); + } +``` # 参考链接 diff --git a/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments/Pasted image 20250528152307.png b/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments/Pasted image 20250528152307.png new file mode 100644 index 0000000..461000d Binary files /dev/null and b/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments/Pasted image 20250528152307.png differ diff --git a/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments/Pasted image 20250528152414.png b/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments/Pasted image 20250528152414.png new file mode 100644 index 0000000..f261a46 Binary files /dev/null and b/docs/docs/guide/10.项目实战/10.1-模块驱动案例/10.1.2-SG90舵机/attachments/Pasted image 20250528152414.png differ