diff --git a/examples/peripherals/mcpwm/mcpwm_servo_control/README.md b/examples/peripherals/mcpwm/mcpwm_servo_control/README.md index 262539d6bb..671cb13bff 100644 --- a/examples/peripherals/mcpwm/mcpwm_servo_control/README.md +++ b/examples/peripherals/mcpwm/mcpwm_servo_control/README.md @@ -1,22 +1,59 @@ -| Supported Targets | ESP32 | -| ----------------- | ----- | +| Supported Targets | ESP32 | ESP32-S3 | +| ----------------- | ----- | -------- | +# MCPWM RC Servo Control Example -# MCPWM servo motor control Example +(See the README.md file in the upper level 'examples' directory for more information about examples.) -This example will show you how to use MCPWM module to control servo motor - -Assign pulse width range and the maximum degree, accordingly the servo will move from 0 to maximum degree continuously - +This example illustrates how to drive a typical [RC Servo](https://en.wikipedia.org/wiki/Servo_(radio_control)) 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. -## Step 1: Pin assignment -* GPIO18 is assigned as the MCPWM signal for servo motor +## How to Use Example + +### Hardware Required + +* A development board with any Espressif SoC which features MCPWM peripheral (e.g., ESP32-DevKitC, ESP-WROVER-KIT, etc.) +* A USB cable for Power supply and programming +* A RC servo motor, e.g. [SG90](http://www.ee.ic.ac.uk/pcheung/teaching/DE1_EE/stores/sg90_datasheet.pdf) + +Connection : + +``` ++-------+ +-----------------+ +| | | | +| +-+ GPIO18++ PWM(Orange) +----------+ | +| ESP |---5V------+ Vcc(Red) +--------------| Servo Motor | +| +---------+ GND(Brown) +----------+ | +| | | | ++-------+ +-----------------+ +``` + +### Build and Flash + +Run `idf.py -p PORT flash monitor` to build, flash and monitor the project. + +(To exit the serial monitor, type ``Ctrl-]``.) + +See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects. -## Step 2: Connection -* connect GPIO18 with servo pwm signal -* other two wires of servo motor are VCC and GND +## Example Output +Run the example, you will see the following output log: -## Step 3: Initialize MCPWM -* You need to set the frequency(generally 50 Hz) and duty cycle of MCPWM timer -* You need to set the MCPWM channel you want to use, and bind the channel with one of the timers +``` +... +I (0) cpu_start: Starting scheduler on APP CPU. +I (349) example: Angle of rotation: -90 +I (449) example: Angle of rotation: -89 +I (549) example: Angle of rotation: -88 +I (649) example: Angle of rotation: -87 +I (749) example: Angle of rotation: -86 +... +``` + +The servo will rotate from -90 degree to 90 degree, and then turn back again. + +## 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. diff --git a/examples/peripherals/mcpwm/mcpwm_servo_control/main/CMakeLists.txt b/examples/peripherals/mcpwm/mcpwm_servo_control/main/CMakeLists.txt index fda5dd827e..010d6a1d47 100644 --- a/examples/peripherals/mcpwm/mcpwm_servo_control/main/CMakeLists.txt +++ b/examples/peripherals/mcpwm/mcpwm_servo_control/main/CMakeLists.txt @@ -1,2 +1,2 @@ -idf_component_register(SRCS "mcpwm_servo_control_example.c" +idf_component_register(SRCS "mcpwm_servo_control_example_main.c" INCLUDE_DIRS ".") diff --git a/examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example.c b/examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example.c deleted file mode 100644 index 88841f252f..0000000000 --- a/examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example.c +++ /dev/null @@ -1,77 +0,0 @@ -/* servo motor control example - - 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 - -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "esp_attr.h" - -#include "driver/mcpwm.h" -#include "soc/mcpwm_periph.h" - -//You can get these value from the datasheet of servo you use, in general pulse width varies between 1000 to 2000 mocrosecond -#define SERVO_MIN_PULSEWIDTH 1000 //Minimum pulse width in microsecond -#define SERVO_MAX_PULSEWIDTH 2000 //Maximum pulse width in microsecond -#define SERVO_MAX_DEGREE 90 //Maximum angle in degree upto which servo can rotate - -static void mcpwm_example_gpio_initialize(void) -{ - printf("initializing mcpwm servo control gpio......\n"); - mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, 18); //Set GPIO 18 as PWM0A, to which servo is connected -} - -/** - * @brief Use this function to calcute pulse width for per degree rotation - * - * @param degree_of_rotation the angle in degree to which servo has to rotate - * - * @return - * - calculated pulse width - */ -static uint32_t servo_per_degree_init(uint32_t degree_of_rotation) -{ - uint32_t cal_pulsewidth = 0; - cal_pulsewidth = (SERVO_MIN_PULSEWIDTH + (((SERVO_MAX_PULSEWIDTH - SERVO_MIN_PULSEWIDTH) * (degree_of_rotation)) / (SERVO_MAX_DEGREE))); - return cal_pulsewidth; -} - -/** - * @brief Configure MCPWM module - */ -void mcpwm_example_servo_control(void *arg) -{ - uint32_t angle, count; - //1. mcpwm gpio initialization - mcpwm_example_gpio_initialize(); - - //2. initial mcpwm configuration - printf("Configuring Initial Parameters of mcpwm......\n"); - mcpwm_config_t pwm_config; - pwm_config.frequency = 50; //frequency = 50Hz, i.e. for every servo motor time period should be 20ms - pwm_config.cmpr_a = 0; //duty cycle of PWMxA = 0 - pwm_config.cmpr_b = 0; //duty cycle of PWMxb = 0 - pwm_config.counter_mode = MCPWM_UP_COUNTER; - pwm_config.duty_mode = MCPWM_DUTY_MODE_0; - mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); //Configure PWM0A & PWM0B with above settings - while (1) { - for (count = 0; count < SERVO_MAX_DEGREE; count++) { - printf("Angle of rotation: %d\n", count); - angle = servo_per_degree_init(count); - printf("pulse width: %dus\n", angle); - mcpwm_set_duty_in_us(MCPWM_UNIT_0, MCPWM_TIMER_0, MCPWM_OPR_A, angle); - vTaskDelay(10); //Add delay, since it takes time for servo to rotate, generally 100ms/60degree rotation at 5V - } - } -} - -void app_main(void) -{ - printf("Testing servo motor.......\n"); - xTaskCreate(mcpwm_example_servo_control, "mcpwm_example_servo_control", 4096, NULL, 5, NULL); -} diff --git a/examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example_main.c b/examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example_main.c new file mode 100644 index 0000000000..0c11a6db84 --- /dev/null +++ b/examples/peripherals/mcpwm/mcpwm_servo_control/main/mcpwm_servo_control_example_main.c @@ -0,0 +1,47 @@ +/* Servo Motor control example + + 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/task.h" +#include "esp_log.h" +#include "driver/mcpwm.h" + +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 +#define SERVO_MIN_PULSEWIDTH_US (1000) // Minimum pulse width in microsecond +#define SERVO_MAX_PULSEWIDTH_US (2000) // Maximum pulse width in microsecond +#define SERVO_MAX_DEGREE (90) // Maximum angle in degree upto which servo can rotate + +#define SERVO_PULSE_GPIO (18) // GPIO connects to the PWM signal line + +static inline uint32_t example_convert_servo_angle_to_duty_us(int angle) +{ + return (angle + SERVO_MAX_DEGREE) * (SERVO_MAX_PULSEWIDTH_US - SERVO_MIN_PULSEWIDTH_US) / (2 * SERVO_MAX_DEGREE) + SERVO_MIN_PULSEWIDTH_US; +} + +void app_main(void) +{ + mcpwm_gpio_init(MCPWM_UNIT_0, MCPWM0A, SERVO_PULSE_GPIO); // To drive a RC servo, one MCPWM generator is enough + + mcpwm_config_t pwm_config = { + .frequency = 50, // frequency = 50Hz, i.e. for every servo motor time period should be 20ms + .cmpr_a = 0, // duty cycle of PWMxA = 0 + .counter_mode = MCPWM_UP_COUNTER, + .duty_mode = MCPWM_DUTY_MODE_0, + }; + mcpwm_init(MCPWM_UNIT_0, MCPWM_TIMER_0, &pwm_config); + + while (1) { + for (int angle = -SERVO_MAX_DEGREE; angle < SERVO_MAX_DEGREE; angle++) { + ESP_LOGI(TAG, "Angle of rotation: %d", 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))); + vTaskDelay(pdMS_TO_TICKS(100)); //Add delay, since it takes time for servo to rotate, generally 100ms/60degree rotation under 5V power supply + } + } +}