Control a differential-drive robot wirelessly using ROS2 Humble on a Linux PC and Micro-ROS on an ESP32 over WiFi UDP. Drive two DC motors via an L298N H-Bridge with full keyboard teleop support.
๐ Quick Start โข ๐ Wiring โข ๐ป Code Overview โข ๐ง Troubleshooting โข ๐ References
mini_bot_ros2_esp32/
โโโ ๐ arduino/
โ โโโ ๐ ESP32_L298N_MicroROS_CmdVel_WiFi/ โ โ
Main sketch (WiFi/UDP)
โ โ โโโ ESP32_L298N_MicroROS_CmdVel_WiFi.ino
โ โโโ ๐ microros_cmd_vel_serial/ โ Serial/USB fallback
โ โโโ microros_cmd_vel_serial.ino
โโโ ๐ docs/
โ โโโ wiring_diagram.md
โ โโโ troubleshooting.md
โ โโโ led_status.md
โโโ ๐ scripts/
โ โโโ setup_microros_agent.sh โ One-time setup script
โ โโโ run_agent_wifi.sh
โ โโโ run_agent_serial.sh
โ โโโ run_teleop.sh
โโโ README.md
| Component | Specification | Notes |
|---|---|---|
| ESP32 Dev Module | Any 38-pin ESP32 | Use Espressif board v2.0.2 in Arduino IDE |
| L298N Motor Driver | Dual H-Bridge, 2A/ch | 12V input; has onboard 5V regulator |
| DC Motors ร 2 | 3Vโ12V with gearbox | Match voltage to battery |
| 12V Battery | Li-Ion or NiMH | Powers L298N & motors |
| USB Cable | Micro-USB or USB-C | Flash ESP32 via Arduino IDE |
| WiFi Router | 2.4 GHz 802.11 b/g/n | |
| Robot Chassis | 2WD differential | Any standard 2-wheel platform |
# ROS2 Humble (Ubuntu 22.04)
sudo apt install ros-humble-desktop
# Build tools
sudo apt install python3-colcon-common-extensions python3-rosdep2
# Teleop keyboard
sudo apt install ros-humble-teleop-twist-keyboardAlso required:
- Arduino IDE 2.x
- ESP32 board support v2.0.2 (via Arduino Boards Manager)
micro_ros_arduinolibrary (via Arduino Library Manager)
git clone https://github.com/YOUR_USERNAME/mini_bot_ros2_esp32.git
cd mini_bot_ros2_esp32chmod +x scripts/setup_microros_agent.sh
./scripts/setup_microros_agent.sh๐ What this script does (click to expand)
# Creates ~/microros_ws workspace
mkdir -p ~/microros_ws/src
cd ~/microros_ws/src
# Clones micro-ROS-Agent (humble branch)
git clone -b humble https://github.com/micro-ROS/micro-ROS-Agent.git
# Installs dependencies & builds
cd ~/microros_ws
rosdep install --from-paths src --ignore-src -y
colcon build
source install/setup.bash- Open Arduino IDE โ File โ Preferences
- Add to Additional Board Manager URLs:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json - Tools โ Board โ Boards Manager โ search
ESP32โ install ESP32 by Espressif Systems v2.0.2 - Sketch โ Include Library โ Manage Libraries โ search
micro_ros_arduinoโ install
๐ Reference: Installing ESP32 in Arduino IDE
Open arduino/ESP32_L298N_MicroROS_CmdVel_WiFi/ESP32_L298N_MicroROS_CmdVel_WiFi.ino and edit these 4 lines:
const char* ssid = "YOUR_WIFI_SSID"; // Your WiFi name
const char* password = "YOUR_WIFI_PASSWORD"; // Your WiFi password
const char* agent_ip = "192.168.1.100"; // Your PC's IP (run: hostname -I)
const int agent_port = 8888; // Keep as 8888In Arduino IDE:
- Tools โ Board โ
ESP32 Dev Module - Tools โ Port โ
/dev/ttyUSB0(or/dev/ttyACM0) - Click Upload โถ
If port is not visible:
sudo usermod -aG dialout $USER(then log out and back in)
# Terminal 1 โ Micro-ROS Agent
./scripts/run_agent_wifi.sh
# Terminal 2 โ Keyboard Control
./scripts/run_teleop.sh
# Power on ESP32 โ auto-connects WiFi โ LED blinks 1 Hz โ ready! โ
| ESP32 GPIO | L298N Pin | Wire | Function |
|---|---|---|---|
GPIO 5 |
ENA |
๐ต Blue | Right Motor Speed (PWM) |
GPIO 18 |
IN1 |
๐ข Green | Right Motor Direction 1 |
GPIO 19 |
IN2 |
๐ก Yellow | Right Motor Direction 2 |
GPIO 4 |
ENB |
๐ต Blue | Left Motor Speed (PWM) |
GPIO 16 |
IN3 |
๐ข Green | Left Motor Direction 1 |
GPIO 17 |
IN4 |
๐ก Yellow | Left Motor Direction 2 |
GND |
GND |
โซ Black | Common Ground (required!) |
| L298N Terminal | Connection |
|---|---|
OUT1 & OUT2 |
Right Motor |
OUT3 & OUT4 |
Left Motor |
12V input |
Battery positive |
GND |
Battery negative + ESP32 GND |
5V output |
ESP32 5V pin (optional) |
โ ๏ธ Always connect common GND between ESP32 and L298N โ without it, motor direction signals will not work correctly.
๐ Reference: ESP32 Pinout Reference | L298N Tutorial
[ Keyboard ]
โ
โผ
[ teleop_twist_keyboard ]
โ /cmd_vel (geometry_msgs/Twist)
โผ
[ micro_ros_agent ] โ runs on PC (UDP port 8888)
โ
WiFi (UDP)
โ
โผ
[ ESP32 + Micro-ROS ]
โ
โโโโ Left Motor (ENB / IN3 / IN4)
โโโโ Right Motor (ENA / IN1 / IN2)
// /cmd_vel provides:
// linear.x โ forward/backward (+positive = forward)
// angular.z โ rotation (+positive = turn left / CCW)
float left_speed = linear_x - angular_z;
float right_speed = linear_x + angular_z;
// Both constrained to [-1.0, +1.0]
// Multiplied by SPEED_SCALE (default 0.8)
// Converted to PWM 0โ255 via ledcWrite()linear.x |
angular.z |
Robot Motion |
|---|---|---|
+ |
0 |
Forward |
- |
0 |
Backward |
0 |
+ |
Spin Left (CCW) |
0 |
- |
Spin Right (CW) |
+ |
+ |
Forward + Left arc |
+ |
- |
Forward + Right arc |
0 |
0 |
Stop |
โโโโโโโโโโโโโโโโโโโ
โ WAITING_AGENT โ โ LED slow blink, ping agent every 1s
โโโโโโโโโโฌโโโโโโโโโ
ping OK โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ AGENT_AVAILABLE โ โ Create node, subscriber, timer, executor
โโโโโโโโโโฌโโโโโโโโโ
success โ
โผ
โโโโโโโโโโโโโโโโโโโ
โ AGENT_CONNECTED โ โ LED 1Hz blink, spin executor, drive motors
โโโโโโโโโโฌโโโโโโโโโ
ping failโ
โผ
โโโโโโโโโโโโโโโโโโโโโโโ
โ AGENT_DISCONNECTED โ โ Stop motors, destroy entities
โโโโโโโโโโโโโโโโโโโโฌโโโ
โโโโโโโโโโโโโโโโโโโโโโโโ WAITING_AGENT
// โโ WiFi โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* agent_ip = "192.168.1.100"; // PC IP
const int agent_port = 8888;
// โโ Motor Pins โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
#define ENA 5 // Right Motor PWM speed
#define IN1 18 // Right Motor Direction 1
#define IN2 19 // Right Motor Direction 2
#define ENB 4 // Left Motor PWM speed
#define IN3 16 // Left Motor Direction 1
#define IN4 17 // Left Motor Direction 2
// โโ Tuning โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
#define SPEED_SCALE 0.8 // Reduce if robot moves too fast (0.0โ1.0)
#define PWM_FREQ 5000 // 5 kHz PWM
#define PWM_RES 8 // 8-bit โ 0โ255 u i o
j k l
m , .
| Key | Action |
|---|---|
i |
โฌ๏ธ Forward |
, |
โฌ๏ธ Backward |
j |
โฌ ๏ธ Turn Left |
l |
โก๏ธ Turn Right |
k |
โน๏ธ STOP |
u / o |
|
m / . |
|
q / z |
Increase / decrease max speed |
w / x |
Increase / decrease linear speed only |
e / c |
Increase / decrease angular speed only |
| LED Pattern | Meaning |
|---|---|
| โก Fast blink ร 5 | Startup โ GPIO initializing |
| ๐ต Slow blink | Connecting to WiFi... |
| ๐ข Steady ON | WiFi connected, waiting for agent |
| ๐ข Regular blink (1 Hz) | โ Ready โ connected to ROS2 agent |
| ๐ด Fast continuous blink | โ ERROR โ check agent & serial monitor |
WiFi Router: 192.168.1.1
โโโ PC (Ubuntu): 192.168.1.100 โ runs micro-ros-agent on UDP :8888
โโโ ESP32: 192.168.1.150 โ auto-assigned via DHCP
hostname -I
# or: ip addr show wlan0 | grep "inet "sudo ufw allow 8888/udp
sudo ufw statusAdd before WiFi.begin() in the sketch:
IPAddress local_IP(192, 168, 1, 150);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
WiFi.config(local_IP, gateway, subnet);| Feature | WiFi (UDP) โ Recommended | Serial (USB) |
|---|---|---|
| Cable required | โ No | โ Yes |
| Range | 50+ meters | USB length |
| Auto-reconnect | โ Yes (state machine) | โ Manual reset |
| Multiple robots | โ Yes | One per port |
| Latency | ~1โ5 ms | ~1โ2 ms |
| Best for | Final use, demos | Initial setup, debug |
โ Garbled Serial output ( โฏโฏโฏโฏโฏโฏ )
Cause: Baud rate mismatch โ code uses 115200 but Serial Monitor is set to 9600
Fix:
- In Arduino IDE โ Serial Monitor โ change
9600โ115200 - Press RESET on ESP32
This is a Serial Monitor display issue only โ nothing to do with WiFi or Micro-ROS.
โ ESP32 won't connect to WiFi
- Double-check SSID and password (case-sensitive)
- Make sure your router broadcasts 2.4 GHz โ ESP32 does not support 5 GHz
- Add debug output:
// After Serial.begin(115200):
Serial.print("WiFi status: ");
Serial.println(WiFi.status());
// 3 = connected, 6 = wrong password, 1 = no SSID foundโ micro-ROS agent not receiving data
# 1. Confirm your PC's IP matches the sketch
hostname -I
# 2. Allow UDP port through firewall
sudo ufw allow 8888/udp
# 3. Run agent with maximum verbosity
ros2 run micro_ros_agent micro_ros_agent udp4 --port 8888 -v6
# 4. Verify port is open and listening
sudo netstat -tulpn | grep 8888
# 5. Both devices must be on the same network
ping <ESP32_IP_ADDRESS>โ Motors not responding
- Verify GPIO numbers in sketch match your actual wiring
- Ensure GND is connected between ESP32 and L298N (common ground)
- Check L298N has 12V power from battery
- Remove ENA/ENB jumpers from L298N โ the code controls speed via PWM
- Try increasing
SPEED_SCALEcloser to1.0 - Test motors independently with a simple blink-style Arduino sketch first
โ Connection drops frequently
Add these lines after WiFi.begin():
WiFi.setSleep(false); // Disable WiFi power save mode
WiFi.setTxPower(WIFI_POWER_19_5dBm); // Maximum transmit powerโ colcon build fails โ FastDDS target conflict
Error message:
Some (but not all) targets in this export set were already defined.
Targets Defined: eProsima_atomic
Targets not yet defined: fastrtps
Root cause: Ubuntu ships FastRTPS 2.5.x; ROS Humble needs FastDDS 2.6.x โ both are installed simultaneously and CMake gets confused.
Fix โ run in order:
# 1. Remove Ubuntu's conflicting FastRTPS packages
sudo apt remove --purge -y \
libfastrtps-dev libfastrtps2.5 \
libfastcdr-dev libfastcdr1
# 2. Clean leftover CMake config files
sudo rm -rf /usr/lib/x86_64-linux-gnu/cmake/fastrtps
sudo rm -rf /usr/lib/x86_64-linux-gnu/cmake/fastdds
sudo ldconfig
# 3. Reinstall correct ROS Humble DDS packages
sudo apt install --reinstall -y \
ros-humble-fastrtps \
ros-humble-fastcdr \
ros-humble-rmw-fastrtps-cpp
# 4. Wipe workspace and rebuild from scratch
cd ~/microros_ws
rm -rf build install log
# 5. Source ONLY ROS Humble (NOT /usr/local/setup.bash)
source /opt/ros/humble/setup.bash
# 6. Rebuild
colcon build --symlink-install
โ ๏ธ Rule of Thumb: Never installlibfastrtps-devfrom Ubuntu repos when using ROS 2 Humble. Always useros-humble-fastrtps.
โ /dev/ttyUSB0 not visible or permission denied
# List all serial devices
ls /dev/tty*
# Add yourself to the dialout group (one-time โ requires logout/login)
sudo usermod -aG dialout $USER
# Quick temporary fix (resets on reboot)
sudo chmod 666 /dev/ttyUSB0Once everything is set up, use these commands every session:
# โโ Terminal 1: Start Agent โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
cd ~/microros_ws && source install/setup.bash
ros2 run micro_ros_agent micro_ros_agent udp4 --port 8888
# โโ Terminal 2: Keyboard Control โโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
source /opt/ros/humble/setup.bash
ros2 run teleop_twist_keyboard teleop_twist_keyboard
# โโ Terminal 3: Verify Everything โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
ros2 node list # โ /esp32_robot_wifi
ros2 topic list # โ /cmd_vel
ros2 topic info /cmd_vel # โ Subscription count: 1
# โโ Manual Test Commands โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Move forward
ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist "{linear: {x: 0.2}}"
# Turn left
ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist "{angular: {z: 0.5}}"
# Stop
ros2 topic pub --once /cmd_vel geometry_msgs/msg/Twist "{}"| Resource | Link |
|---|---|
| Micro-ROS Arduino Library | https://github.com/micro-ROS/micro_ros_arduino |
| Micro-ROS Agent | https://github.com/micro-ROS/micro-ROS-Agent |
| ROS2 Humble Documentation | https://docs.ros.org/en/humble/ |
| ESP32 Pinout Reference | https://lastminuteengineers.com/esp32-pinout-reference/ |
| L298N + ESP32 Video Tutorial | https://youtu.be/2JTMqURJTwg |
| Installing ESP32 in Arduino IDE | https://randomnerdtutorials.com/installing-the-esp32-board-in-arduino-ide-windows-instructions/ |
| teleop_twist_keyboard | https://github.com/ros2/teleop_twist_keyboard |
| Micro-ROS Docs | https://micro.ros.org/docs/overview/ |
Mini Bot v1.0 ย |ย ROS2 Humble ย |ย ESP32 ย |ย Micro-ROS