RADU: Control the Robot using a Joystick
Tags: robots, raspberrypi
Published: 2022-05-02 05:12:08

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](https://admantium.com/blog/robo14_controlling_with_a_joystick/)_.

## 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.

```bash
[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:

```bash
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:

```bash
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 ...

```bash
rosrun joy joy_node dev:=/dev/input/js0
```

... and you should see this output.

```bash
[ 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.

```bash
$> rostopic echo /joy

header: 
  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](http://wiki.ros.org/joy).

## 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 ...

```bash
rosrun teleop_twist_joy teleop_node 
```

... and you should see the following output.

```bash
[ 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:

![](https://admantium.com/images/blog/robo14_rqt_all_nodes.png)

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](http://wiki.ros.org/joy), 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:

```bash
---
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.