Xbox Wireless Controller Teleoperation on ROS Noetic

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 initialized
  • IndentationError: 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