A mobile robot offers many interfaces for controlling. In my project RADU, a two-wheel movable robot, I implemented a wrap for movements commands from the Robot Operating System ROS. Commands have two parts in which we are interested: The linear velocity in meter/second, which moves the robot along its x-axis, and the angular velocity on radians/second, which turns the robot around its z-axis, also called pitch. Any controller that sends input which can be converted to these movements messages is usable by the project.
This article is a quick tutorial how to use a game console controller, from a PlayStation or Xbox, to move a robot. You will learn how to connect and read gamepad data, and how to convert it to ROS compatible commands.
The technical context of this article is Ubuntu 20.04 LTS
with latest ros-noetic
and Python 3.8.10
.
This article originally appeared at my blog admantium.com.
Connect and Read Gamepad Data
We need to connect a gamepad and check that your Linux system correctly recognizes it. Use whatever gamepad you have — in my case, it’s a PlayStation 3 controller, and plug it into a USB port
Then, run the Linux command dmesg
to show decent Kernel messages about the detected device.
[412373.206747] usb 1-2: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[412373.206749] usb 1-2: Product: PLAYSTATION(R)3 Controller
[412373.206751] usb 1-2: Manufacturer: Sony
[412373.562080] input: Sony PLAYSTATION(R)3 Controller Motion Sensors as /devices/pci0000:00/0000:00:15.0/usb1/1-2/1-2:1.0/0003:054C:0268.001C/input/input102
[412373.624511] input: Sony PLAYSTATION(R)3 Controller as /devices/pci0000:00/0000:00:15.0/usb1/1-2/1-2:1.0/0003:054C:0268.001C/input/input101
[412373.625435] sony 0003:054C:0268.001C: input,hiddev1,hidraw3: USB HID v81.11 Joystick [Sony PLAYSTATION(R)3 Controller] on usb-0000:00:15.0-2/input0
Next, we need to figure out where joystick data can be accessed. Execute the command cat /proc/bus/input/devices
and look for a text block that mentions the controller that you connected. In my case, I see this:
I: Bus=0003 Vendor=054c Product=0268 Version=8111
N: Name="Sony PLAYSTATION(R)3 Controller"
P: Phys=usb-0000:00:15.0-3.1/input0
S: Sysfs=/devices/pci0000:00/0000:00:15.0/usb1/1-3/1-3.1/1-3.1:1.0/0003:054C:0268.0059/input/input224
U: Uniq=00:21:4f:08:f6:c8
H: Handlers=event17 js0
B: PROP=0
B: EV=20001b
B: KEY=f00000000 0 0 0 7fdb000000000000 0 0 0 0
B: ABS=3f
B: MSC=10
B: FF=107030000 0
In the line p
, we see /input0
, and in line H
, we see js0
. We combine this information to the device file /dev/input/js0
. This device file provides a byte stream about controller commands.
Now, we will read this byte stream with ROS.
Reading Gamepad Data with ROS
In order to work with any gamepad, we need to install additional ROS packages. In a terminal, execute this command:
sudo apt-get install ros-noetic-joy-teleop ros-noetic-teleop-twist-joy ros-noetic-joy
These packages provide several ways to interact with a connected joypad. To get started, we will run a ROS node called joy_node
with the parameter of the detected device file. Run the following command ...
rosrun joy joy_node dev:=/dev/input/js0
… and you should see this output.
[ INFO] [1627219939.885877257]: Opened joystick: /dev/input/js0 (Sony PLAYSTATION(R)3 Controller). deadzone_: 0.050000.
This node published data at the topic /joy
. Let’s subscribe to this topic and see the messages.
$> rostopic echo /joyheader:
seq: 177
stamp:
secs: 1627219968
nsecs: 437779598
frame_id: "/dev/input/js0"
axes: [0.04505977779626846, -0.0, 0.0, -0.0, -0.0, 0.0]
buttons: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
---
header:
seq: 178
stamp:
secs: 1627219968
nsecs: 447620065
frame_id: "/dev/input/js0"
axes: [-0.0, -0.0, 0.0, -0.0, -0.0, 0.0]
buttons: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
---
Each message contains two vectors. The first vector axes
contains the left/right and top/down position of the two control sticks and the cross key as float values. The second vector buttons
contains integer values about which buttons are pressed. See the button mapping documentation.
Converting Gamepad Data to Twist Messages
The last step is to translate the messages from the /joy
topic to TWIST messages. Another ROS package already performs this translation, we just need to start the teleop_twist_joy
node.
Start the node with …
rosrun teleop_twist_joy teleop_node
… and you should see the following output.
[ INFO] [1627221588.156287628]: Teleop enable button 0.
[ INFO] [1627221588.161486651]: Linear axis x on 1 at scale 0.500000.
[ INFO] [1627221588.161570308]: Angular axis yaw on 0 at scale 0.500000.
Before continuing, be sure to check that all required ROS nodes are running and connected as shown in the following picture:
Subscribe to the topic /cmd_vel
. Then, on your gamepad, identify the deadman switch
button, a safe guard to prevent sending commands that you did not intent. From the above mentioned message Teleop enable button 0.
and the button mapping documentation, I can see that this button is X
on my PlayStation 3 controller.
Now comes the big moment: Hold down the X
button, move the joystick, and you should see these messages:
---
linear:
x: 0.036096855998039246
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: -0.5
---
linear:
x: -0.0
y: 0.0
z: 0.0
angular:
x: 0.0
y: 0.0
z: -0.45583534240722656
Cool! Now you just need feed these messages to your robot, and you can start moving around, controlled with a gamepad.
Conclusion
This article showed you how to use a gamepad for controlling your robot. We learned how to identify a connected controller on Linux by reading the build-in proc log to identify which device file represents the controller. Then we continued to install the required ROS packages joy-teleop
and teleop-twist-joy
and started a simple node that shows which game stick or buttons are pressed. And with the help of another node we can transform these messages to movement messages in the Twist format. Now, grab your favourite controller and move your robot in realtime.