ESP32/ESP32-S3

ESP-IDF ESP32 (ESP32-S3) 스태핑 모터 RMT 제어 DM556 모터 드라이버

devkoko32 2025. 4. 20. 14:58

ESP32 S3 와 DM556 을 사용해서 스태핑 모터를 제어하는 방법이다.

다른 ESP32시리즈나 A4988 등 다른 드라이버를 사용해도 동일과정으로 구동할 수 있다.

VSCODE 에서 ESP-IDF 프레임워크를 사용한 방식이다.

 


ESP-IDF Welcome 페이지에서 New Project생성 후 탬플릿 선택에서 ESP-IDF 선택하고 step 을 검색하면 RMT 를 사용한 스태핑 모터 드라이벙 제어 예제가 나온다.

 

 

 

 

 

기본적으로 DRV8825 를 기준으로 한 예제 소스코드가 생성되고 이 상태에서 사용하는 드라이버나 핀에 알맞게 연결해서 사용 할 수 있다.

 

 

 

 

 

 

 

 

연결 모습

에노드 방식으로 연결 했고 ESP32 S3 를 전압 변경 없이 직접 연결했다.

DM556 에는 시그널 입력을 5~24V 입력하도록 되어있으나 테스트삼아 3.3v 로 직접 연결 했는데 간단한 테스트하기에 무리는 없는것 같다.

 

물론 드라이버의 전원은 24V 를 공급 해줘야 한다.

 

 

 

 

 

 

 

주의해야할 점은 처음 구동할 때 저속으로 제어하려고 

 

#define STEP_MOTOR_RESOLUTION_HZ 을 100 으로 수정하고 빌드 - 플래쉬하는 과정에는 문제가 없었으나

플래쉬 후 모니터링 해보니 clock divider 값이 유효 범위(1~256)를 벗어났다는 오류와 함께 지속적으로 재부팅 되는 문제가 있었다.

 

큰 수정 없이 사용 가능한 최저속도는 312500Hz 로 테스트할 수 있다.

 

 

 

 

 

 

테스트 소스코드

/*
 * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/rmt_tx.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "stepper_motor_encoder.h"

// DM556 연결 방식으로 수정한 핀 정보
#define STEP_MOTOR_GPIO_ENA 6
#define STEP_MOTOR_GPIO_DIR 5
#define STEP_MOTOR_GPIO_STEP 4

// Common Anode 방식으로 연결 시
#define STEP_MOTOR_ENABLE_LEVEL 1 // ENA 핀이 HIGH 여야 모터가 동작한다는것을 저장
#define STEP_MOTOR_SPIN_DIR_CLOCKWISE 0 //DIR은 LOW 일 때 시계방향임을 저장
#define STEP_MOTOR_SPIN_DIR_COUNTERCLOCKWISE !STEP_MOTOR_SPIN_DIR_CLOCKWISE // 반시계방향인 경우 !STEP_MOTOR_SPIN_DIR_CLOCKWISE 임

// #define STEP_MOTOR_RESOLUTION_HZ 312500 // 최저속도
#define STEP_MOTOR_RESOLUTION_HZ 1000000


static const char *TAG = "example";

void app_main(void)
{
    ESP_LOGI(TAG, "Initialize EN + DIR GPIO");
    gpio_config_t en_dir_gpio_config = {
        .mode = GPIO_MODE_OUTPUT,
        .intr_type = GPIO_INTR_DISABLE,
        .pin_bit_mask = 1ULL << STEP_MOTOR_GPIO_DIR | 1ULL << STEP_MOTOR_GPIO_ENA,
    };
    ESP_ERROR_CHECK(gpio_config(&en_dir_gpio_config));

    ESP_LOGI(TAG, "Create RMT TX channel");
    rmt_channel_handle_t motor_chan = NULL;
    rmt_tx_channel_config_t tx_chan_config = {
        .clk_src = RMT_CLK_SRC_DEFAULT, // select clock source
        .gpio_num = STEP_MOTOR_GPIO_STEP,
        .mem_block_symbols = 64,
        .resolution_hz = STEP_MOTOR_RESOLUTION_HZ,
        .trans_queue_depth = 10, // set the number of transactions that can be pending in the background
    };
    ESP_ERROR_CHECK(rmt_new_tx_channel(&tx_chan_config, &motor_chan));

    ESP_LOGI(TAG, "Set spin direction");
    gpio_set_level(STEP_MOTOR_GPIO_DIR, STEP_MOTOR_SPIN_DIR_CLOCKWISE);
    ESP_LOGI(TAG, "Enable step motor");
    gpio_set_level(STEP_MOTOR_GPIO_ENA, STEP_MOTOR_ENABLE_LEVEL);

    ESP_LOGI(TAG, "Create motor encoders");
    stepper_motor_curve_encoder_config_t accel_encoder_config = {
        .resolution = STEP_MOTOR_RESOLUTION_HZ,
        .sample_points = 500,
        .start_freq_hz = 500,
        .end_freq_hz = 1500,
    };
    rmt_encoder_handle_t accel_motor_encoder = NULL;
    ESP_ERROR_CHECK(rmt_new_stepper_motor_curve_encoder(&accel_encoder_config, &accel_motor_encoder));

    stepper_motor_uniform_encoder_config_t uniform_encoder_config = {
        .resolution = STEP_MOTOR_RESOLUTION_HZ,
    };
    rmt_encoder_handle_t uniform_motor_encoder = NULL;
    ESP_ERROR_CHECK(rmt_new_stepper_motor_uniform_encoder(&uniform_encoder_config, &uniform_motor_encoder));

    stepper_motor_curve_encoder_config_t decel_encoder_config = {
        .resolution = STEP_MOTOR_RESOLUTION_HZ,
        .sample_points = 500,
        .start_freq_hz = 1500,
        .end_freq_hz = 500,
    };
    rmt_encoder_handle_t decel_motor_encoder = NULL;
    ESP_ERROR_CHECK(rmt_new_stepper_motor_curve_encoder(&decel_encoder_config, &decel_motor_encoder));

    ESP_LOGI(TAG, "Enable RMT channel");
    ESP_ERROR_CHECK(rmt_enable(motor_chan));

    ESP_LOGI(TAG, "Spin motor for 6000 steps: 500 accel + 5000 uniform + 500 decel");
    rmt_transmit_config_t tx_config = {
        .loop_count = 0,
    };

    const static uint32_t accel_samples = 500;
    const static uint32_t uniform_speed_hz = 1500;
    const static uint32_t decel_samples = 500;

    while (1)
    {
        // acceleration phase
        tx_config.loop_count = 0;
        ESP_ERROR_CHECK(rmt_transmit(motor_chan, accel_motor_encoder, &accel_samples, sizeof(accel_samples), &tx_config));

        // uniform phase
        tx_config.loop_count = 5000;
        ESP_ERROR_CHECK(rmt_transmit(motor_chan, uniform_motor_encoder, &uniform_speed_hz, sizeof(uniform_speed_hz), &tx_config));

        // deceleration phase
        tx_config.loop_count = 0;
        ESP_ERROR_CHECK(rmt_transmit(motor_chan, decel_motor_encoder, &decel_samples, sizeof(decel_samples), &tx_config));
        // wait all transactions finished
        ESP_ERROR_CHECK(rmt_tx_wait_all_done(motor_chan, -1));

        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}