Decentralized Robotics: Integrating ESP32 with ROS 2 via micro-ROS

 

Building a complex robot—like a quadruped or an autonomous rover—requires two different types of computing. You need high-level "Brain" computing (for computer vision and path planning, usually done in Python on a Raspberry Pi) and low-level "Spine" computing (for real-time motor control and sensor reading, usually done in C++ on an ESP32).

Academic research in distributed robotics solves this communication problem using the Robot Operating System (ROS). In this article, we will look at the theory of Publisher/Subscriber networks and apply it by bridging an ESP32 to a ROS 2 network using micro-ROS.

The Academic Theory: The Publisher/Subscriber Model

Unlike traditional HTTP or serial communication where one device explicitly asks another for data, ROS utilizes a decentralized Publisher/Subscriber (Pub/Sub) architecture running over Data Distribution Service (DDS).

In this theory, nodes (individual programs) do not need to know about each other. An ESP32 simply acts as a Publisher, shouting sensor data into a designated "Topic" (e.g., /robot/imu). Any other node on the network—like a Python script acting as a Subscriber—can listen to that topic and process the data. This decoupled architecture is what allows modern robotics to scale without bottlenecks.

The Engineering Application: micro-ROS on the ESP32

Historically, ROS was too heavy to run on microcontrollers. However, the development of micro-ROS allows embedded devices to act as native ROS 2 nodes over Wi-Fi or Serial.

Here is how an embedded developer writes C++ code to turn an ESP32 into a micro-ROS publisher that broadcasts data to the wider robotics network.

The C++ Code

C++
#include <micro_ros_arduino.h>
#include <stdio.h>
#include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <std_msgs/msg/int32.h>

// ROS 2 core components
rcl_publisher_t publisher;
std_msgs__msg__Int32 msg;
rclc_support_t support;
rcl_allocator_t allocator;
rcl_node_t node;
rcl_timer_t timer;
rclc_executor_t executor;

// Timer callback: This runs repeatedly to publish data
void timer_callback(rcl_timer_t * timer, int64_t last_call_time) {
  RCLC_UNUSED(last_call_time);
  if (timer != NULL) {
    // Populate the message (e.g., reading a sensor value)
    msg.data++; 
    
    // Publish the message to the ROS 2 network
    rcl_publish(&publisher, &msg, NULL);
  }
}

void setup() {
  // Connect to the micro-ROS agent over Wi-Fi
  set_microros_wifi_transports("YOUR_SSID", "YOUR_PASSWORD", "192.168.1.100", 8888);
  
  delay(2000);

  allocator = rcl_get_default_allocator();

  // Initialize micro-ROS support
  rclc_support_init(&support, 0, NULL, &allocator);

  // Create a ROS 2 Node named "esp32_sensor_node"
  rclc_node_init_default(&node, "esp32_sensor_node", "", &support);

  // Create a Publisher on the topic "sensor_data"
  rclc_publisher_init_default(
    &publisher,
    &node,
    ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32),
    "sensor_data");

  // Create a timer that fires every 1000ms (1 Hz)
  rclc_timer_init_default(
    &timer,
    &support,
    RCL_MS_TO_NS(1000),
    timer_callback);

  // Create an executor to manage the timer
  rclc_executor_init(&executor, &support.context, 1, &allocator);
  rclc_executor_add_timer(&executor, &timer);
  
  msg.data = 0;
}

void loop() {
  // Spin the executor to handle ROS 2 communication
  rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100));
}

Practical Considerations

Setting up micro-ROS requires a host machine (like a laptop or Raspberry Pi) running a micro-ROS-agent. The ESP32 connects to this agent, which bridges the microcontroller's lightweight protocol into the full ROS 2 DDS ecosystem. This architecture is the industry standard for bridging the gap between hardware limitations and advanced AI planning.

by Malik Hassan

Post a Comment

0 Comments
* Please Don't Spam Here. All the Comments are Reviewed by Admin.