micro-ROS / micro-ROS/micro_ros_arduino
ESP32 CAM not sending any data to ROS2 Jazzy, even though topic is visible and rqt graph is right
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 576
- Forks
- 146
- PR merge metrics
- No merged PRs in 30d
Description
## Issue template
- Hardware description: ESP32 CAM
- RTOS: FreeRTOS
- Installation type: Arduino IDE
- Version or commit hash: Jazzy
#### Steps to reproduce the issue
1. Run these command on your ROS2 terminal:
```
$ source ~/microros_ws/install/local_setup.sh
$ ros2 run micro_ros_agent micro_ros_agent udp4 --port 8888 --buf-size 8192
```
2. Burn the given Arduino IDE code to the ESP32 CAM module, the camera is OV2640. Put the WiFi credentials also, and put your ROS2 terminal IP address in the code.
```
#include
#include
#include
#include
#include
#include
#include
#include
#define LED_PIN 13
// Camera Pin Configurations
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
rcl_publisher_t image_publisher;
sensor_msgs__msg__CompressedImage img_msg;
rclc_support_t support;
rcl_allocator_t allocator;
rcl_node_t node;
#define RCCHECK(fn) \
{ \
rcl_ret_t temp_rc = fn; \
if ((temp_rc != RCL_RET_OK)) { \
Serial.printf("[ERROR] RCCHECK failed: %d\n", temp_rc); \
error_loop(); \
} \
}
#define RCSOFTCHECK(fn) \
{ \
rcl_ret_t temp_rc = fn; \
if ((temp_rc != RCL_RET_OK)) { \
Serial.printf("[WARN] RCSOFTCHECK failed: %d\n", temp_rc); \
return; \
} \
}
void error_loop() {
while (1) {
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
delay(100);
}
}
void capture_and_publish_image() {
Serial.println("[INFO] Capturing image...");
camera_fb_t *fb = esp_camera_fb_get();
if (!fb) {
Serial.println("[ERROR] Camera capture failed!");
return;
}
Serial.printf("[INFO] Captured image of size: %d bytes\n", fb->len);
if (!rcl_publisher_is_valid(&image_publisher)) {
Serial.println("[ERROR] Publisher initialization failed! Retrying...");
rcl_publisher_fini(&image_publisher, &node);
rclc_publisher_init_default(
&image_publisher,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(sensor_msgs, msg, CompressedImage),
"esp32_cam/image");
}
img_msg.format.data = (char *)"jpeg";
img_msg.format.size = strlen("jpeg");
img_msg.header.stamp.sec = rmw_uros_epoch_millis() / 1000;
img_msg.header.stamp.nanosec = (rmw_uros_epoch_millis() % 1000) * 1000000;
// Use a static buffer to prevent memory fragmentation
static uint8_t img_buffer[10000];
if (fb->len > sizeof(img_buffer)) {
Serial.println("[ERROR] Image too large, skipping...");
esp_camera_fb_return(fb);
return;
}
memcpy(img_buffer, fb->buf, fb->len);
img_msg.data.data = img_buffer;
img_msg.data.size = fb->len;
Serial.println("[INFO] Image data copied successfully.");
int max_retries = 3;
for (int attempt = 1; attempt <= max_retries; attempt++) {
rcl_ret_t pub_status = rcl_publish(&image_publisher, &img_msg, NULL);
if (pub_status == RCL_RET_OK) {
Serial.println("[INFO] Image published successfully.");
break;
} else {
Serial.printf("[ERROR] Image publish failed (Attempt %d/%d) with error code: %d\n", attempt, max_retries, pub_status);
delay(500);
}
}
esp_camera_fb_return(fb);
Serial.println("[INFO] Image memory released.");
}
void capture_and_publish_image() {
Serial.println("[INFO] Capturing image...");
camera_fb_t * fb = esp_camera_fb_get();
if (!fb) {
Serial.println("[ERROR] Camera capture failed!");
return;
}
if (fb->len == 0) {
Serial.println("[ERROR] Captured image has size 0! Skipping...");
esp_camera_fb_return(fb);
return;
}
Serial.printf("[INFO] Captured image of size: %d bytes\n", fb->len);
img_msg.format.data = (char *)"jpeg";
img_msg.format.size = 4;
img_msg.data.data = (uint8_t*)malloc(fb->len);
if (img_msg.data.data == NULL) {
Serial.println("[ERROR] Memory allocation failed!");
esp_camera_fb_return(fb);
return;
}
memcpy(img_msg.data.data, fb->buf, fb->len);
img_msg.data.size = fb->len;
Serial.println("[INFO] Image data copied successfully.");
rcl_ret_t ret = rcl_publish(&image_publisher, &img_msg, NULL);
if (ret == RCL_RET_OK) {
Serial.println("[INFO] Image published successfully.");
} else {
Serial.printf("[ERROR] Image publish failed with error code: %d\n", ret);
}
free(img_msg.data.data);
esp_camera_fb_return(fb);
Serial.println("[INFO] Image memory released.");
}
void setup() {
Serial.begin(115200);
Serial.println("[INFO] Setting up WiFi transport...");
set_microros_wifi_transports("WiFI_SSID", "WiFi_Password", "xx.xx.xx.xx_ROS2_IP", 8888);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, HIGH);
delay(2000);
Serial.println("[INFO] Configuring camera...");
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_sccb_sda = SIOD_GPIO_NUM;
config.pin_sccb_scl = SIOC_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
config.frame_size = FRAMESIZE_QVGA;
config.jpeg_quality = 20;
config.fb_count = 1;
if (esp_camera_init(&config) != ESP_OK) {
Serial.println("[ERROR] Camera init failed!");
error_loop();
}
Serial.println("[INFO] Camera initialized successfully.");
allocator = rcl_get_default_allocator();
RCCHECK(rclc_support_init(&support, 0, NULL, &allocator));
RCCHECK(rclc_node_init_default(&node, "micro_ros_arduino_wifi_node", "", &support));
if (!rcl_publisher_is_valid(&image_publisher)) {
Serial.println("[ERROR] Publisher is invalid! Retrying setup...");
rcl_publisher_fini(&image_publisher, &node);
rclc_publisher_init_best_effort(
&image_publisher,
&node,
ROSIDL_GET_MSG_TYPE_SUPPORT(sensor_msgs, msg, CompressedImage),
"esp32_cam/image");
}
Serial.println("[INFO] ESP32-CAM setup complete.");
}
void loop() {
Serial.println("[INFO] Loop start.");
capture_and_publish_image();
Serial.println("[INFO] Loop end. Waiting before next capture...");
delay(10000);
}
```
#### Expected behavior
The topics data shall be visible under this command:
`$ ros2 topic echo /esp32_cam/image
`
#### Actual behavior
The output is blank from above command
#### Additional information
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Reproduce the issue with the micro_ros_agent command, ros2 topic echo /esp32_cam/image, and the Arduino sketch's setup(), loop(), and capture_and_publish_image() paths. Check the serial output alongside topic visibility to identify where publishing stops; done means /esp32_cam/image produces image messages instead of blank output.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- arduino, c
- Domain
- embedded-iot, robotics
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 38/100