In the past few chapters, we have used ROS to control mobile, armed, flying, and simulated robots. The similarities and differences between these robots have been discussed and we have shown the commonality that ROS has created between all these robot types. Commonality is not only in the structure of the software and the communications methods, but also in the simulation environment and the tools used for visualization and analysis.
The influence of ROS goes even further to provide a common interface to control devices external to the robot. These devices include game controllers (gamepads and joystick controllers), mobile devices (smart phones and tablets), and even controller boards (the Arduino and Raspberry Pi).
In this chapter, you will learn about the following topics:
If you have played with the joystick with either Baxter or Crazyflie, you may think that the function of certain buttons or joysticks would be better with your own special design. Each type of game controller has one or more joysticks and various buttons or triggers to cause events depending on the game software being used. Here, for the Microsoft Xbox controller, we will do the following:
jstest-gtk
jstest
; this will enable you to determine the corresponding numbers of controller joysticks, buttons, and triggersThe ensuing diagram shows the Xbox 360 game controller. Pushing a button changes the output from 0 (off) to 1 (on) on the channel corresponding to the pushed button, which in turn can be read by a program and used to start an application. Moving the stick outputs a numerical value that can be used to control a robot. The joystick movements are described by the axis of the movement; moving the stick up and down defines one axis, and moving the stick to the left and right defines another.
To determine the number of the channel or axis associated with a button or joystick of a game controller, the graphical program jstest-gtk
can be used. The package
jstest-gtk
is a game controller testing and configuration tool. This package is described at https://launchpad.net/ubuntu/trusty/+package/jstest-gtk.
To download and install the package, use the following command:
$ sudo apt-get install jstest-gtk
The command to execute the program is:
$ jstest-gtk
The following screenshot shows the result with the Xbox controller connected to our computer. As shown, the Microsoft Xbox 360 controller has 8 axes and 11 buttons:
By double-clicking on the name Generic X-Box pad, a GUI for the axes and buttons of the Xbox 360 controller appears, as in the following screenshot:
As you push a button on the controller, the number of the button will be highlighted in the display. The relative position of a joystick that is moved is shown graphically, and the numerical value associated with the motion is also displayed. More details on this are provided at http://manpages.ubuntu.com/manpages/trusty/en/man1/jstest-gtk.1.html.
As an alternative to the graphical display of the game controller properties, terminal commands can be used. First, plug your game controller into a USB port of your computer and then determine the devices connected to the computer by issuing this command:
$ ls /dev/input/
The output should be similar to the following:
by-id event0 event10 event2 event4 event6 event8 js0 mouse0 by-path event1 event11 event3 event5 event7 event9 mice
The game controller will appear as a js device in this listing. Note that the system has the game controller as js0 in the list. To test the controller and determine the index number of the axes and buttons, type the following command:
$ jstest /dev/input/js0
The output for the Xbox controller, should be similar to the following:
Driver version is 2.1.0. Joystick (Generic X-Box pad) has 8 axes (X, Y, Z, Rx, Ry, Rz, Hat0X, Hat0Y) and 11 buttons (BtnX, BtnY, BtnTL, BtnTR, BtnTR2, BtnSelect, BtnThumbL, BtnThumbR, ?, ?, ?). Testing ... (interrupt to exit) Axes: 0: 0 1: 0 2: 0 3: 0 4: 0 5: 0 6: 0 7: 0 Buttons: 0:off 1:off 2:off 3:off 4:off 5:off 6:off 7:off 8:off 9:off 10:off
In this case, the controller is the Xbox controller. Experiment with your controller to understand the output when the joystick is moved or a button is pressed. When a button is pressed, the corresponding value changes to on
. Also, when a joystick is moved horizontally or vertically, the selected axis value will change from its initial value to a new value.
Now for your controller, you can figure out which buttons or axes you will use for your application. Next, you must consider the type of software or hardware that is to be controlled by the game controller. For ROS, the /joy
node is used to read the controller output.
A tutorial describing the use of Ubuntu commands is available at http://wiki.ros.org/joy/Tutorials/ConfiguringALinuxJoystick.
ROS has a driver for a generic controller with a joystick. The joy
package contains the /joy
node that interfaces a generic Linux joystick to ROS. This node publishes a joy
message, which contains the current state of each one of the joystick's buttons and axes. Before using the /joy
node in an application, see whether you have the joy
package installed by typing this:
$ rospack find joy
The output should be as follows:
/opt/ros/indigo/share/joy
If you do not see the path to the joy
package, install it with this command:
$ sudo apt-get install ros-indigo-joy
In this section, an example use of a game controller and the /joy
node is presented utilizing the following code files:
turtlesim_teleop.launch
that executes three nodes: /joy
, turtlesim
, and turtlesim_joy
. A Python program turtlesim_joy.py
initiates the turtlesim_joy
node and allows the joystick to control the movement of the turtle on the screen.turtlesim_joy.py
calls another Python program called move_circle.py
when a button is pushed on the controller.The Turtlesim simulator was introduced in the Turtlesim, the first ROS robot simulation section in Chapter 1, Getting Started with ROS. If you wish to create an ROS package for this example, refer to the instructions in the Creating and building a ROS package section in Chapter 2, Creating Your First Two-Wheeled ROS Robot (in Simulation). In our case, the files are copied to the ros_robotics
package created in Chapter 2, Creating Your First Two-Wheeled ROS Robot (in Simulation).
Downloading the example code
You can download the example code files and other support material for this book from www.PacktPub.com.
In the package directory, the launch file should be copied to a /launch
directory. The Python code should be copied to a /src
directory of the package. Make sure the Python scripts are executable by issuing the following command:
$ chmod +x <filename>.py
Here, <filename>
is the name of the Python script. Alternatively, type the following:
$ chmod +x *.py
You can use the preceding command to make all the Python files in the directory executable.
After loading the files into the directories, issue the catkin_make
command in the catkin workspace directory to link together the ROS files.
The code for the launch file turtlesim_teleop.launch
is as follows:
<?xml version="1.0"?> <launch> <!-- turtlesim and joy node--> <node name="turtlesim" pkg="turtlesim" type="turtlesim_node"/> <node name="joy" pkg="joy" type="joy_node"/> <!-- turtlesim_joy node interfaces Xbox controller to turtlesim --> <node name="turtlesim_joy" pkg="ros_robotics" type="turtlesim_joy.py" output="screen"/> </launch>
Use the following command to launch the nodes:
$ roslaunch ros_robotics turtlesim_teleop.launch
You should see output similar to the following (edited):
. . SUMMARY ======== PARAMETERS * /rosdistro: indigo * /rosversion: 1.11.19 NODES / joy (joy/joy_node) turtlesim (turtlesim/turtlesim_node) turtlesim_joy (ros_robotics/turtlesim_joy.py) auto-starting new master process[master]: started with pid [22649] ROS_MASTER_URI=http://localhost:11311 .
The preceding command will launch three ROS nodes as shown in the screen output after the launch file is executed with the roslaunch
command. You can also check the list of nodes with this command:
$ rosnode list
The first Python program turtlesim_joy.py
allows the turtle of Turtlesim to be controlled by the joystick axes [0]
and [1]
on the game controller. For the Xbox controller, these axes correspond to the vertical and horizontal left joystick movements, respectively. In addition, pushing the button corresponding to button number 0
will cause another Python program, move_circle.py
, to drive the turtle in a circle. On the Xbox controller, this is the green button:
#!/usr/bin/env python """ Node converts joystick inputs into commands for Turtlesim """ import rospy from geometry_msgs.msg import Twist from sensor_msgs.msg import Joy from move_circle import move_circle def joy_listener(): # start node rospy.init_node("turtlesim_joy", anonymous=True) # subscribe to joystick messages on topic "joy" rospy.Subscriber("joy", Joy, tj_callback, queue_size=1) # keep node alive until stopped rospy.spin() # called when joy message is received def tj_callback(data): # start publisher of cmd_vel to control Turtlesim pub = rospy.Publisher("turtle1/cmd_vel", Twist, queue_size=1) # Create Twist message & add linear x and angular z from left joystick twist = Twist() twist.linear.x = data.axes[1] twist.angular.z = data.axes[0] # record values to log file and screen rospy.loginfo("twist.linear: %f ; angular %f", twist.linear.x, twist.angular.z) # process joystick buttons if data.buttons[0] == 1: # green button on xbox controller move_circle() # publish cmd_vel move command to Turtlesim pub.publish(twist) if __name__ == '__main__': try: joy_listener() except rospy.ROSInterruptException: pass
This code initializes the turtlesim_joy
node and subscribes to the joy
topic. When a joy message is received, the tj_callback
function reads the values from axes[0]
and axes[1]
and assigns them to a twist
message. If the value of button[0]
is 1
, then this button was pressed and the move_circle
function is called.
The listing of move_circle.py
is as follows:
#!/usr/bin/env python """ Script to move Turtlesim in a circle """ import rospy from geometry_msgs.msg import Twist def move_circle(): # Create a publisher which can "talk" to Turtlesim and tell it to move pub = rospy.Publisher('turtle1/cmd_vel', Twist, queue_size=1) # Create a Twist message and add linear x and angular z values move_cmd = Twist() move_cmd.linear.x = 1.0 move_cmd.angular.z = 1.0 # Save current time and set publish rate at 10 Hz now = rospy.Time.now() rate = rospy.Rate(10) # For the next 6 seconds publish cmd_vel move commands to Turtlesim while rospy.Time.now() < now + rospy.Duration.from_sec(6): pub.publish(move_cmd) rate.sleep() if __name__ == '__main__': try: move_circle() except rospy.ROSInterruptException: pass
When executed, this code will create a twist
message and set the linear.x
and angular.z
values. As the Python program turtlesim_joy.py
is executed, you can move the turtle with the joystick. As the selected button is pushed, move_circle.py
is executed, and the turtle then turns with a linear velocity of 1.0
units/second and an angular velocity of 1
radian/second for 6
seconds. Thus, the turtle moves in a circle. The following screenshot shows the result of one of our experiments with the Xbox 360 joystick control of Turtlesim:
To see the message published by the /joy
node, issue this command:
$ rostopic echo /joy
The results indicate the values of the axes and buttons and other information:
header: seq: 218 stamp: secs: 1461884528 nsecs: 370878390 frame_id: '' axes: [-0.0, 0.1265602558851242, 0.0, -0.06729009747505188, -0.0, 0.0, 0.0, 0.0] buttons: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Move the stick to start and use Ctrl + C to end the output.
To see the nodes and topics, issue the following command:
$ rqt_graph
This yields the resulting screenshot:
A tutorial using a C++ program and a launch file for use with a Turtlesim and joystick is available at http://wiki.ros.org/joy/Tutorials/WritingTeleopNode.