example: update servo example with new driver API

This commit is contained in:
morris
2022-05-28 17:05:36 +08:00
parent 6751b229f1
commit 1557a533fe
4 changed files with 115 additions and 43 deletions

View File

@@ -4,7 +4,7 @@
(See the README.md file in the upper level 'examples' directory for more information about examples.) (See the README.md file in the upper level 'examples' directory for more information about examples.)
This example illustrates how to drive a typical [RC Servo](https://en.wikipedia.org/wiki/Servo_%28radio_control%29) by sending a PWM signal using the MCPWM driver. The PWM pulse has a frequency of 50Hz (period of 20ms), and the active-high time (which controls the rotation) ranges from 1ms to 2ms with 1.5ms always being center of range. This example illustrates how to drive a typical [RC Servo](https://en.wikipedia.org/wiki/Servo_%28radio_control%29) by sending a PWM signal using the MCPWM driver. The PWM pulse has a frequency of 50Hz (period of 20ms), and the active-high time (which controls the rotation) ranges from 0.5s to 2.5ms with 1.5ms always being center of range.
## How to Use Example ## How to Use Example
@@ -17,15 +17,16 @@ This example illustrates how to drive a typical [RC Servo](https://en.wikipedia.
Connection : Connection :
``` ```
+-------+ +-----------------+ ESP Board Servo Motor 5V
| | | | +-------------------+ +---------------+ ^
| +-+ GPIO18++ PWM(Orange) +----------+ | | SERVO_PULSE_GPIO +-----+PWM VCC +----+
| ESP |---5V------+ Vcc(Red) +--------------| Servo Motor | | | | |
| +---------+ GND(Brown) +----------+ | | GND +-----+GND |
| | | | +-------------------+ +---------------+
+-------+ +-----------------+
``` ```
Note that, some kind of servo might need a higher current supply than the development board usually can provide. It's recommended to power the servo separately.
### Build and Flash ### Build and Flash
Run `idf.py -p PORT flash monitor` to build, flash and monitor the project. Run `idf.py -p PORT flash monitor` to build, flash and monitor the project.
@@ -42,11 +43,22 @@ Run the example, you will see the following output log:
``` ```
... ...
I (0) cpu_start: Starting scheduler on APP CPU. I (0) cpu_start: Starting scheduler on APP CPU.
I (349) example: Angle of rotation: -90 I (305) example: Create timer and operator
I (449) example: Angle of rotation: -89 I (305) example: Connect timer and operator
I (549) example: Angle of rotation: -88 I (305) example: Create comparator and generator from the operator
I (649) example: Angle of rotation: -87 I (315) gpio: GPIO[44]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (749) example: Angle of rotation: -86 I (325) example: Set generator action on timer and compare event
I (335) example: Enable and start timer
I (335) example: Angle of rotation: 0
I (1345) example: Angle of rotation: 2
I (2345) example: Angle of rotation: 4
I (3345) example: Angle of rotation: 6
I (4345) example: Angle of rotation: 8
I (5345) example: Angle of rotation: 10
I (6345) example: Angle of rotation: 12
I (7345) example: Angle of rotation: 14
I (8345) example: Angle of rotation: 16
I (9345) example: Angle of rotation: 18
... ...
``` ```
@@ -54,6 +66,4 @@ The servo will rotate from -90 degree to 90 degree, and then turn back again.
## Troubleshooting ## Troubleshooting
Note that, some kind of servo might need a higher current supply than the development board usually can provide. It's recommended to power the servo separately.
For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon. For any technical queries, please open an [issue] (https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you soon.

View File

@@ -1,47 +1,93 @@
/* Servo Motor control example /*
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "esp_log.h" #include "esp_log.h"
#include "driver/mcpwm.h" #include "driver/mcpwm_prelude.h"
static const char *TAG = "example"; static const char *TAG = "example";
// You can get these value from the datasheet of servo you use, in general pulse width varies between 1000 to 2000 mocrosecond // Please consult the datasheet of your servo before changing the following parameters
#define SERVO_MIN_PULSEWIDTH_US (1000) // Minimum pulse width in microsecond #define SERVO_MIN_PULSEWIDTH_US 500 // Minimum pulse width in microsecond
#define SERVO_MAX_PULSEWIDTH_US (2000) // Maximum pulse width in microsecond #define SERVO_MAX_PULSEWIDTH_US 2500 // Maximum pulse width in microsecond
#define SERVO_MAX_DEGREE (90) // Maximum angle in degree upto which servo can rotate #define SERVO_MIN_DEGREE -90 // Minimum angle
#define SERVO_MAX_DEGREE 90 // Maximum angle
#define SERVO_PULSE_GPIO (18) // GPIO connects to the PWM signal line #define SERVO_PULSE_GPIO 0 // GPIO connects to the PWM signal line
#define SERVO_TIMEBASE_RESOLUTION_HZ 1000000 // 1MHz, 1us per tick
#define SERVO_TIMEBASE_PERIOD 20000 // 20000 ticks, 20ms
static inline uint32_t example_convert_servo_angle_to_duty_us(int angle) static inline uint32_t example_angle_to_compare(int angle)
{ {
return (angle + SERVO_MAX_DEGREE) * (SERVO_MAX_PULSEWIDTH_US - SERVO_MIN_PULSEWIDTH_US) / (2 * SERVO_MAX_DEGREE) + SERVO_MIN_PULSEWIDTH_US; return (angle - SERVO_MIN_DEGREE) * (SERVO_MAX_PULSEWIDTH_US - SERVO_MIN_PULSEWIDTH_US) / (SERVO_MAX_DEGREE - SERVO_MIN_DEGREE) + SERVO_MIN_PULSEWIDTH_US;
} }
void app_main(void) void app_main(void)
{ {
mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, SERVO_PULSE_GPIO); // To drive a RC servo, one MCPWM generator is enough ESP_LOGI(TAG, "Create timer and operator");
mcpwm_timer_handle_t timer = NULL;
mcpwm_config_t pwm_config = { mcpwm_timer_config_t timer_config = {
.frequency = 50, // frequency = 50Hz, i.e. for every servo motor time period should be 20ms .group_id = 0,
.cmpr_a = 0, // duty cycle of PWMxA = 0 .clk_src = MCPWM_TIMER_CLK_SRC_DEFAULT,
.counter_mode = MCPWM_UP_COUNTER, .resolution_hz = SERVO_TIMEBASE_RESOLUTION_HZ,
.duty_mode = MCPWM_DUTY_MODE_0, .period_ticks = SERVO_TIMEBASE_PERIOD,
.count_mode = MCPWM_TIMER_COUNT_MODE_UP,
}; };
mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); ESP_ERROR_CHECK(mcpwm_new_timer(&timer_config, &timer));
mcpwm_oper_handle_t operator = NULL;
mcpwm_operator_config_t operator_config = {
.group_id = 0, // operator must be in the same group to the timer
};
ESP_ERROR_CHECK(mcpwm_new_operator(&operator_config, &operator));
ESP_LOGI(TAG, "Connect timer and operator");
ESP_ERROR_CHECK(mcpwm_operator_connect_timer(operator, timer));
ESP_LOGI(TAG, "Create comparator and generator from the operator");
mcpwm_cmpr_handle_t comparator = NULL;
mcpwm_comparator_config_t comparator_config = {
.flags.update_cmp_on_tez = true,
};
ESP_ERROR_CHECK(mcpwm_new_comparator(operator, &comparator_config, &comparator));
mcpwm_gen_handle_t generator = NULL;
mcpwm_generator_config_t generator_config = {
.gen_gpio_num = SERVO_PULSE_GPIO,
};
ESP_ERROR_CHECK(mcpwm_new_generator(operator, &generator_config, &generator));
// set the initial compare value, so that the servo will spin to the center position
ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparator, example_angle_to_compare(0)));
ESP_LOGI(TAG, "Set generator action on timer and compare event");
// go high on counter empty
ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_timer_event(generator,
MCPWM_GEN_TIMER_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, MCPWM_TIMER_EVENT_EMPTY, MCPWM_GEN_ACTION_HIGH),
MCPWM_GEN_TIMER_EVENT_ACTION_END()));
// go low on compare threshold
ESP_ERROR_CHECK(mcpwm_generator_set_actions_on_compare_event(generator,
MCPWM_GEN_COMPARE_EVENT_ACTION(MCPWM_TIMER_DIRECTION_UP, comparator, MCPWM_GEN_ACTION_LOW),
MCPWM_GEN_COMPARE_EVENT_ACTION_END()));
ESP_LOGI(TAG, "Enable and start timer");
ESP_ERROR_CHECK(mcpwm_timer_enable(timer));
ESP_ERROR_CHECK(mcpwm_timer_start_stop(timer, MCPWM_TIMER_START_NO_STOP));
int angle = 0;
int step = 2;
while (1) { while (1) {
for (int angle = -SERVO_MAX_DEGREE; angle < SERVO_MAX_DEGREE; angle++) { ESP_LOGI(TAG, "Angle of rotation: %d", angle);
ESP_LOGI(TAG, "Angle of rotation: %d", angle); ESP_ERROR_CHECK(mcpwm_comparator_set_compare_value(comparator, example_angle_to_compare(angle)));
ESP_ERROR_CHECK(mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, example_convert_servo_angle_to_duty_us(angle))); //Add delay, since it takes time for servo to rotate, usually 200ms/60degree rotation under 5V power supply
vTaskDelay(pdMS_TO_TICKS(100)); //Add delay, since it takes time for servo to rotate, generally 100ms/60degree rotation under 5V power supply vTaskDelay(pdMS_TO_TICKS(500));
if ((angle + step) > 60 || (angle + step) < -60) {
step *= -1;
} }
angle += step;
} }
} }

View File

@@ -0,0 +1,17 @@
# SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.esp32
@pytest.mark.esp32s3
@pytest.mark.generic
def test_servo_mg996r_example(dut: Dut) -> None:
dut.expect_exact('example: Create timer and operator')
dut.expect_exact('example: Connect timer and operator')
dut.expect_exact('example: Create comparator and generator from the operator')
dut.expect_exact('example: Set generator action on timer and compare event')
dut.expect_exact('example: Enable and start timer')
dut.expect_exact('example: Angle of rotation: 0')

View File

@@ -1773,7 +1773,6 @@ examples/peripherals/i2c/i2c_tools/main/cmd_i2ctools.h
examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c examples/peripherals/i2c/i2c_tools/main/i2ctools_example_main.c
examples/peripherals/ledc/ledc_basic/main/ledc_basic_example_main.c examples/peripherals/ledc/ledc_basic/main/ledc_basic_example_main.c
examples/peripherals/ledc/ledc_fade/main/ledc_fade_example_main.c examples/peripherals/ledc/ledc_fade/main/ledc_fade_example_main.c
examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example_main.c
examples/peripherals/sdio/host/main/app_main.c examples/peripherals/sdio/host/main/app_main.c
examples/peripherals/sdio/sdio_test.py examples/peripherals/sdio/sdio_test.py
examples/peripherals/sdio/slave/main/app_main.c examples/peripherals/sdio/slave/main/app_main.c