Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ micro_ros_dev
micro_ros_src
esp32_toolchain.cmake
*.a
include
include
dependencies.lock
53 changes: 43 additions & 10 deletions examples/int32_publisher_custom_transport_usbcdc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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)
Expand All @@ -80,16 +113,16 @@ ros2 topic list
Output expected:

```bash
/esp32s2/int32_publisher_usbcdc
/<target>/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 `<target>` 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 /<target>/int32_publisher_usbcdc
```

Output expected:
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
idf_component_register(SRCS "esp_usbcdc_logging.c" INCLUDE_DIRS ".")
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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);

Expand Down
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -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
}
Expand All @@ -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
Original file line number Diff line number Diff line change
@@ -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 <uxr/client/transport.h>
)
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;
Expand All @@ -35,23 +35,23 @@ 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);
return tx_size;
}

// 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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef ESP_USBCDC_TRANSPORT_H
#define ESP_USBCDC_TRANSPORT_H

#include <uxr/client/transport.h>

#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
21 changes: 0 additions & 21 deletions examples/int32_publisher_custom_transport_usbcdc/dependencies.lock

This file was deleted.

16 changes: 8 additions & 8 deletions examples/int32_publisher_custom_transport_usbcdc/main/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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");
Expand Down
Loading