From 559f3dce504facedd35f9a6cb363d6786b525455 Mon Sep 17 00:00:00 2001 From: Narukara Date: Tue, 23 Jun 2026 19:32:18 +0800 Subject: [PATCH] Fix USB-CDC custom transport example Co-authored-by: Mohamed-Sejid --- .gitignore | 3 +- .../README.md | 53 +++++++++++++++---- .../esp32s2_usbcdc_logging/CMakeLists.txt | 1 - .../esp32s2_usbcdc_transport.h | 29 ---------- .../esp_usbcdc_logging/CMakeLists.txt | 1 + .../esp_usbcdc_logging.c} | 6 +-- .../esp_usbcdc_logging.h} | 10 ++-- .../idf_component.yml | 0 .../CMakeLists.txt | 2 +- .../esp_usbcdc_transport.c} | 14 ++--- .../esp_usbcdc_transport.h | 29 ++++++++++ .../idf_component.yml | 0 .../dependencies.lock | 21 -------- .../main/main.c | 16 +++--- 14 files changed, 99 insertions(+), 86 deletions(-) delete mode 100644 examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_logging/CMakeLists.txt delete mode 100644 examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_transport/esp32s2_usbcdc_transport.h create mode 100644 examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_logging/CMakeLists.txt rename examples/int32_publisher_custom_transport_usbcdc/components/{esp32s2_usbcdc_logging/esp32s2_usbcdc_logging.c => esp_usbcdc_logging/esp_usbcdc_logging.c} (88%) rename examples/int32_publisher_custom_transport_usbcdc/components/{esp32s2_usbcdc_logging/esp32s2_usbcdc_logging.h => esp_usbcdc_logging/esp_usbcdc_logging.h} (73%) rename examples/int32_publisher_custom_transport_usbcdc/components/{esp32s2_usbcdc_logging => esp_usbcdc_logging}/idf_component.yml (100%) rename examples/int32_publisher_custom_transport_usbcdc/components/{esp32s2_usbcdc_transport => esp_usbcdc_transport}/CMakeLists.txt (63%) rename examples/int32_publisher_custom_transport_usbcdc/components/{esp32s2_usbcdc_transport/esp32s2_usbcdc_transport.c => esp_usbcdc_transport/esp_usbcdc_transport.c} (77%) create mode 100644 examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_transport/esp_usbcdc_transport.h rename examples/int32_publisher_custom_transport_usbcdc/components/{esp32s2_usbcdc_transport => esp_usbcdc_transport}/idf_component.yml (100%) delete mode 100644 examples/int32_publisher_custom_transport_usbcdc/dependencies.lock diff --git a/.gitignore b/.gitignore index c0453262..9e76854c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ micro_ros_dev micro_ros_src esp32_toolchain.cmake *.a -include \ No newline at end of file +include +dependencies.lock diff --git a/examples/int32_publisher_custom_transport_usbcdc/README.md b/examples/int32_publisher_custom_transport_usbcdc/README.md index 7536afa5..8e03a69e 100644 --- a/examples/int32_publisher_custom_transport_usbcdc/README.md +++ b/examples/int32_publisher_custom_transport_usbcdc/README.md @@ -16,7 +16,14 @@ This example is configured to use the two interfaces of USB-CDC. One interface i ### Hardware Required -This example can be run on any development board that has a USB-CDC interface. +This example can be run on any ESP32-S2 or ESP32-S3 development board that exposes the chip's native USB interface. + +Some development boards have two USB connectors: + +- A USB-to-UART connector, which is commonly used for flashing and serial monitor. +- A native USB connector wired directly to the ESP32-S2/S3 USB pins. + +This example uses the native USB connector at runtime. The application exposes USB-CDC ACM interfaces from the ESP32-S2/S3 itself, so the micro-ROS Agent must be connected to the native USB connector, not to the USB-to-UART connector. ### Configure the project @@ -31,37 +38,63 @@ If you want to use only the micro-ROS communication interface, you need to turn ### Build and Flash > [!NOTE] -> The ESP32-S2/S3 chip needs to be in bootloader mode before it can be detected as a DFU device and flash. This can be achieved by pulling GPIO0 down (e.g., pressing the BOOT button), pulling RESET down for a moment, and releasing GPIO0. +> You can flash the firmware through any supported ESP-IDF flashing interface. If you flash through a USB-to-UART connector, reconnect the board through the native USB connector before running the micro-ROS Agent. #### Build the project -Build DFU image: +```bash +idf.py build +``` + +#### Flash using USB-to-UART + +If your board has a USB-to-UART connector, you can flash the application with the regular ESP-IDF serial flashing flow. Replace `/dev/ttyUSB0` with the actual serial port if needed: ```bash -idf.py dfu +idf.py -p /dev/ttyUSB0 flash ``` -#### Flash the project +After flashing, move the USB cable to the native USB connector before running the example. + +#### Flash using native USB -Put the ESP32-S2/S3 into bootloader mode and run the following command: +If you want to avoid moving the USB cable between flashing and running the example, flash through the native USB connector. + +For ESP32-S2, enter USB DFU bootloader mode by holding BOOT, resetting the board, and then releasing BOOT. Then run: ```bash +idf.py dfu idf.py dfu-flash ``` +For ESP32-S3, the native USB connector commonly enumerates as USB-JTAG/serial in bootloader mode. Replace `/dev/ttyACM0` with the actual USB-JTAG/serial port if needed: + +```bash +idf.py -p /dev/ttyACM0 flash +``` + +After flashing, reset the board and let the application start. With the default configuration, the application exposes two USB-CDC ACM ports over the native USB connector: one for micro-ROS communication and one for log output. + ### Run micro-ROS Agent +Use the micro-ROS communication CDC port from the native USB connector, usually `/dev/ttyACM0`: + ```bash export ROS_DOMAIN_ID=100 # Set the ROS2 domain ID ros2 run micro_ros_agent micro_ros_agent serial --dev /dev/ttyACM0 ``` +Or, using Docker: + +```bash +docker run -it --rm -v /dev:/dev -v /dev/shm:/dev/shm --privileged --net=host microros/micro-ros-agent:rolling serial --dev /dev/ttyACM0 -v4 +``` + Output expected: ```bash [1724443525.673894] info | TermiosAgentLinux.cpp | init | running... | fd: 3 [1724443525.674071] info | Root.cpp | set_verbose_level | logger setup | verbose_level: 4 -[1724443529.936542] info | TermiosAgentLinux.cpp | init | running... | fd: 3 [1724443531.062646] info | Root.cpp | create_client | create | client_key: 0x3E801A05, session_id: 0x81 [1724443531.062805] info | SessionManager.hpp | establish_session | session established | client_key: 0x3E801A05, address: 0 [1724443531.107532] info | ProxyClient.cpp | create_participant | participant created | client_key: 0x3E801A05, participant_id: 0x000(1) @@ -80,16 +113,16 @@ ros2 topic list Output expected: ```bash -/esp32s2/int32_publisher_usbcdc +//int32_publisher_usbcdc /parameter_events /rosout ``` -And see if the `esp32s2/int32_publisher_usbcdc` topic is available. You can echo the topic to see the messages: +The `` part is the configured ESP-IDF target, for example `esp32s2` or `esp32s3`. You can echo the topic to see the messages: ```bash export ROS_DOMAIN_ID=100 # Set the ROS2 domain ID -ros2 topic echo esp32s2/int32_publisher_usbcdc +ros2 topic echo //int32_publisher_usbcdc ``` Output expected: diff --git a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_logging/CMakeLists.txt b/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_logging/CMakeLists.txt deleted file mode 100644 index 5d7b73a2..00000000 --- a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_logging/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -idf_component_register(SRCS "esp32s2_usbcdc_logging.c" INCLUDE_DIRS ".") diff --git a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_transport/esp32s2_usbcdc_transport.h b/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_transport/esp32s2_usbcdc_transport.h deleted file mode 100644 index eb20a202..00000000 --- a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_transport/esp32s2_usbcdc_transport.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef ESP32S2_USBCDC_TRANSPORT_H -#define ESP32S2_USBCDC_TRANSPORT_H - -#include - -#include "tinyusb.h" -#include "tusb_cdc_acm.h" - -#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) - -#ifdef __cplusplus -extern "C" -{ -#endif - -bool esp32s2_usbcdc_open(struct uxrCustomTransport* transport); -bool esp32s2_usbcdc_close(struct uxrCustomTransport* transport); -size_t esp32s2_usbcdc_write(struct uxrCustomTransport* transport, const uint8_t* buf, size_t len, uint8_t* err); -size_t esp32s2_usbcdc_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err); - -#ifdef __cplusplus -} -#endif - -#else -#error "This transport is only supported on ESP32-S2 or ESP32-S3 targets" -#endif // CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 - -#endif // ESP32S2_USBCDC_TRANSPORT_H \ No newline at end of file diff --git a/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_logging/CMakeLists.txt b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_logging/CMakeLists.txt new file mode 100644 index 00000000..f6df52a7 --- /dev/null +++ b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_logging/CMakeLists.txt @@ -0,0 +1 @@ +idf_component_register(SRCS "esp_usbcdc_logging.c" INCLUDE_DIRS ".") diff --git a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_logging/esp32s2_usbcdc_logging.c b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_logging/esp_usbcdc_logging.c similarity index 88% rename from examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_logging/esp32s2_usbcdc_logging.c rename to examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_logging/esp_usbcdc_logging.c index f0c0c7de..4f3d3087 100644 --- a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_logging/esp32s2_usbcdc_logging.c +++ b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_logging/esp_usbcdc_logging.c @@ -1,7 +1,7 @@ -#include "esp32s2_usbcdc_logging.h" +#include "esp_usbcdc_logging.h" // Initialize USB-CDC logging -esp_err_t esp32s2_usbcdc_logging_init(void) +esp_err_t esp_usbcdc_logging_init(void) { const tinyusb_config_t tinyusb_config = { .descriptor = NULL, @@ -38,7 +38,7 @@ esp_err_t esp32s2_usbcdc_logging_init(void) } // Deinitialize USB-CDC logging -esp_err_t esp32s2_usbcdc_logging_deinit(void) +esp_err_t esp_usbcdc_logging_deinit(void) { esp_err_t ret = esp_tusb_deinit_console(TINYUSB_CDC_ACM_1); diff --git a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_logging/esp32s2_usbcdc_logging.h b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_logging/esp_usbcdc_logging.h similarity index 73% rename from examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_logging/esp32s2_usbcdc_logging.h rename to examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_logging/esp_usbcdc_logging.h index ba8193da..06592cb6 100644 --- a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_logging/esp32s2_usbcdc_logging.h +++ b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_logging/esp_usbcdc_logging.h @@ -1,5 +1,5 @@ -#ifndef ESP32S2_USBCDC_LOGGING_H -#define ESP32S2_USBCDC_LOGGING_H +#ifndef ESP_USBCDC_LOGGING_H +#define ESP_USBCDC_LOGGING_H #include "esp_err.h" #include "tinyusb.h" @@ -18,8 +18,8 @@ extern "C" { #endif -esp_err_t esp32s2_usbcdc_logging_init(void); -esp_err_t esp32s2_usbcdc_logging_deinit(void); +esp_err_t esp_usbcdc_logging_init(void); +esp_err_t esp_usbcdc_logging_deinit(void); #ifdef __cplusplus } @@ -29,4 +29,4 @@ esp_err_t esp32s2_usbcdc_logging_deinit(void); #error "Logging over USB-CDC is only supported on ESP32-S2 or ESP32-S3 targets" #endif -#endif // ESP32S2_USBCDC_LOGGING_H +#endif // ESP_USBCDC_LOGGING_H diff --git a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_logging/idf_component.yml b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_logging/idf_component.yml similarity index 100% rename from examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_logging/idf_component.yml rename to examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_logging/idf_component.yml diff --git a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_transport/CMakeLists.txt b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_transport/CMakeLists.txt similarity index 63% rename from examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_transport/CMakeLists.txt rename to examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_transport/CMakeLists.txt index 256799bb..c5fddb03 100644 --- a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_transport/CMakeLists.txt +++ b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_transport/CMakeLists.txt @@ -1,4 +1,4 @@ -idf_component_register(SRCS "esp32s2_usbcdc_transport.c" +idf_component_register(SRCS "esp_usbcdc_transport.c" INCLUDE_DIRS "." REQUIRES micro_ros_espidf_component # include ) diff --git a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_transport/esp32s2_usbcdc_transport.c b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_transport/esp_usbcdc_transport.c similarity index 77% rename from examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_transport/esp32s2_usbcdc_transport.c rename to examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_transport/esp_usbcdc_transport.c index 7bde70d7..0481555d 100644 --- a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_transport/esp32s2_usbcdc_transport.c +++ b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_transport/esp_usbcdc_transport.c @@ -1,7 +1,7 @@ -#include "esp32s2_usbcdc_transport.h" +#include "esp_usbcdc_transport.h" // Open USB-CDC -bool esp32s2_usbcdc_open(struct uxrCustomTransport* transport) { +bool esp_usbcdc_open(struct uxrCustomTransport* transport) { const tinyusb_config_t tinyusb_config = { .device_descriptor = NULL, .string_descriptor = NULL, @@ -12,7 +12,7 @@ bool esp32s2_usbcdc_open(struct uxrCustomTransport* transport) { esp_err_t ret = tinyusb_driver_install(&tinyusb_config); if (ret == ESP_ERR_INVALID_ARG || ret == ESP_FAIL) { - return ret; + return false; } tinyusb_cdcacm_itf_t* cdc_port = (tinyusb_cdcacm_itf_t*)transport->args; @@ -35,13 +35,13 @@ bool esp32s2_usbcdc_open(struct uxrCustomTransport* transport) { } // Close USB-CDC -bool esp32s2_usbcdc_close(struct uxrCustomTransport* transport) { +bool esp_usbcdc_close(struct uxrCustomTransport* transport) { tinyusb_cdcacm_itf_t* cdc_port = (tinyusb_cdcacm_itf_t*)transport->args; return (tusb_cdc_acm_deinit(*cdc_port) == ESP_OK) ? true : false; } // Write to USB-CDC -size_t esp32s2_usbcdc_write(struct uxrCustomTransport* transport, const uint8_t* buf, size_t len, uint8_t* err) { +size_t esp_usbcdc_write(struct uxrCustomTransport* transport, const uint8_t* buf, size_t len, uint8_t* err) { tinyusb_cdcacm_itf_t* cdc_port = (tinyusb_cdcacm_itf_t*)transport->args; size_t tx_size = tinyusb_cdcacm_write_queue(*cdc_port, buf, len); tinyusb_cdcacm_write_flush(*cdc_port, 0); @@ -49,9 +49,9 @@ size_t esp32s2_usbcdc_write(struct uxrCustomTransport* transport, const uint8_t* } // Read from USB-CDC -size_t esp32s2_usbcdc_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err) { +size_t esp_usbcdc_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err) { tinyusb_cdcacm_itf_t* cdc_port = (tinyusb_cdcacm_itf_t*)transport->args; size_t rx_size = 0; esp_err_t ret = tinyusb_cdcacm_read(*cdc_port, buf, len, &rx_size); return (ret == ESP_OK) ? rx_size : 0; -} \ No newline at end of file +} diff --git a/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_transport/esp_usbcdc_transport.h b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_transport/esp_usbcdc_transport.h new file mode 100644 index 00000000..3fe22949 --- /dev/null +++ b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_transport/esp_usbcdc_transport.h @@ -0,0 +1,29 @@ +#ifndef ESP_USBCDC_TRANSPORT_H +#define ESP_USBCDC_TRANSPORT_H + +#include + +#include "tinyusb.h" +#include "tusb_cdc_acm.h" + +#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) + +#ifdef __cplusplus +extern "C" +{ +#endif + +bool esp_usbcdc_open(struct uxrCustomTransport* transport); +bool esp_usbcdc_close(struct uxrCustomTransport* transport); +size_t esp_usbcdc_write(struct uxrCustomTransport* transport, const uint8_t* buf, size_t len, uint8_t* err); +size_t esp_usbcdc_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err); + +#ifdef __cplusplus +} +#endif + +#else +#error "This transport is only supported on ESP32-S2 or ESP32-S3 targets" +#endif // CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 + +#endif // ESP_USBCDC_TRANSPORT_H diff --git a/examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_transport/idf_component.yml b/examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_transport/idf_component.yml similarity index 100% rename from examples/int32_publisher_custom_transport_usbcdc/components/esp32s2_usbcdc_transport/idf_component.yml rename to examples/int32_publisher_custom_transport_usbcdc/components/esp_usbcdc_transport/idf_component.yml diff --git a/examples/int32_publisher_custom_transport_usbcdc/dependencies.lock b/examples/int32_publisher_custom_transport_usbcdc/dependencies.lock deleted file mode 100644 index d0d9ab49..00000000 --- a/examples/int32_publisher_custom_transport_usbcdc/dependencies.lock +++ /dev/null @@ -1,21 +0,0 @@ -dependencies: - espressif/esp_tinyusb: - component_hash: f151d680d6847bfcfd5d8eb6d1c3ff926c208e6b963b2e83643a141bc70baa15 - source: - service_url: https://api.components.espressif.com/ - type: service - version: 1.4.4 - espressif/tinyusb: - component_hash: 214989d502fc168241a4a4f83b097d8ac44a93cd6f1787b4ac10069a8b3bebd3 - source: - service_url: https://api.components.espressif.com/ - type: service - version: 0.15.0~10 - idf: - component_hash: null - source: - type: idf - version: 5.1.2 -manifest_hash: 7f60fd8da9b1e2b73aafbc324107a75ce3928aa50666473c15511b764484240c -target: esp32s2 -version: 1.0.0 diff --git a/examples/int32_publisher_custom_transport_usbcdc/main/main.c b/examples/int32_publisher_custom_transport_usbcdc/main/main.c index 1bec52dd..3dbd5da4 100644 --- a/examples/int32_publisher_custom_transport_usbcdc/main/main.c +++ b/examples/int32_publisher_custom_transport_usbcdc/main/main.c @@ -4,8 +4,8 @@ #include "driver/uart.h" #include "esp_log.h" #include "esp_system.h" -#include "esp32s2_usbcdc_logging.h" -#include "esp32s2_usbcdc_transport.h" +#include "esp_usbcdc_logging.h" +#include "esp_usbcdc_transport.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" @@ -20,7 +20,7 @@ #define DOMAIN_ID 100 #define TIMER_PERIOD 1000 -#define NODE_NAME "esp32s2" +#define NODE_NAME CONFIG_IDF_TARGET #define PUBLISHER_NAME "/int32_publisher_usbcdc" #define TOPIC_NAME NODE_NAME PUBLISHER_NAME @@ -129,7 +129,7 @@ void app_main(void) { // Initialize logging over USB-CDC #if (CONFIG_TINYUSB_CDC_COUNT >= 2) - if (esp32s2_usbcdc_logging_init() == ESP_OK) { + if (esp_usbcdc_logging_init() == ESP_OK) { ESP_LOGI(TAG_MAIN, "USB-CDC Logging initialized"); } #endif @@ -139,10 +139,10 @@ void app_main(void) { rmw_ret_t ret = rmw_uros_set_custom_transport( true, (void *)&cdc_port, - esp32s2_usbcdc_open, - esp32s2_usbcdc_close, - esp32s2_usbcdc_write, - esp32s2_usbcdc_read); + esp_usbcdc_open, + esp_usbcdc_close, + esp_usbcdc_write, + esp_usbcdc_read); if (ret != RMW_RET_OK) { ESP_LOGE(TAG_MAIN, "Fail to set micro-ROS custom transport layer");