Xbox Wireless Controller Teleoperation on ROS Noetic (Raspberry Pi / Ubuntu)
This post documents the exact end-to-end process I followed to achieve butter-smooth teleoperation of a 4WD robot using an Xbox Wireless Controller, Bluetooth, and ROS Noetic. The goal is simple: a complete beginner should be able to reproduce this setup without guesswork.
1. System Overview
Hardware
- Raspberry Pi (Ubuntu 20.04)
- 4WD mobile robot with motor driver
- Xbox Wireless Controller (Bluetooth)
Software
- Ubuntu 20.04 (Focal)
- ROS Noetic
- Python 3
- pygame
- BlueZ (Bluetooth stack)
2. Bluetooth Controller Pairing (Correct Method)
2.1 Start Bluetooth Control
bluetoothctl
Inside the Bluetooth shell:
power on
agent on
default-agent
scan on
Put the Xbox controller into pairing mode (hold the Xbox button + pairing button).
When the controller MAC address appears:
pair XX:XX:XX:XX:XX:XX
trust XX:XX:XX:XX:XX:XX
connect XX:XX:XX:XX:XX:XX
quit
Success indicator: Xbox controller LED becomes solid.
3. Verify Controller at Linux Level
3.1 Confirm Joystick Device
ls /dev/input/js0
Expected output:
/dev/input/js0
3.2 Test Using jstest
jstest /dev/input/js0
Move the sticks and press buttons. You should see axis values and button states change. This confirms Bluetooth and kernel drivers are working correctly.
4. Driver Verification (xpadneo)
Ensure the Xbox Bluetooth driver is loaded:
lsmod | grep xpadneo
Expected:
hid_xpadneo
5. ROS Networking (Clean Setup)
Single Machine Configuration
source /opt/ros/noetic/setup.bash
source ~/catkin_ws/devel/setup.bash
Verify:
env | grep ROS
Expected:
ROS_MASTER_URI=http://localhost:11311
ROS_DISTRO=noetic
6. ROS Workspace Setup
mkdir -p ~/catkin_ws/src
cd ~/catkin_ws
catkin_make
source devel/setup.bash
7. Xbox Teleop ROS Node (Key Fixes)
Problems Encountered
pygame.error: video system not initializedIndentationError: unexpected indent
Root Cause
- pygame requires a display context
- SSH/headless systems have no GUI
Professional Fix (Headless Safe)
Set SDL dummy video driver before importing pygame:
import os
os.environ["SDL_VIDEODRIVER"] = "dummy"
Initialize pygame correctly:
pygame.init()
pygame.display.init()
pygame.display.set_mode((1, 1))
pygame.joystick.init()
8. Running the System (Correct Order)
Terminal 1 — ROS Master
roscore
Terminal 2 — Motor Driver Node
rosrun my_4wd_robot motor_driver_node.py
Terminal 3 — Xbox Teleop Node
rosrun xbox_teleop xbox_teleop_node.py
Expected output:
[INFO] XBOX TELEOP ACTIVE
9. Final Validation
rostopic echo /cmd_vel
Joystick movement should reflect in linear and angular velocity values.
10. Result
- Bluetooth stable
- Zero-lag teleoperation
- Smooth differential drive
- Headless-safe execution
The robot now drives like butter.
11. Lessons Learned
- Always validate hardware at the Linux level first
- Headless systems require dummy video drivers
- Python indentation matters
- ROS networking must be clean before debugging nodes
12. Next Upgrades
- Deadman safety button
- Speed scaling modes
- Launch file automation
- Auto-start on boot
This guide documents a real debugging journey — not a copy-paste tutorial.
Comments
Post a Comment