Robot Programming | Robot Operating System (ROS)

Robot Programming

Robot Programming Using Robot Operating System (ROS) 2019

This blog explains Robot Operating System and robot programming. 

What Is Robot Programming?

Robot Programming

As you know, a robot is a machine with sensors, actuators (motors), and a computing unit that behaves based on user controls, or it can make its own decisions based on sensors inputs.

 

We can say the brain of the robot is a computing unit. It can be a microcontroller or a PC. The decision making and actions of the robot completely depend on the program running the robot’s brain.

 

This program can be firmware running on a microcontroller, or C/C++ or Python code running on a PC or a single board computer, like the Raspberry Pi. Robot programming is the process of making the robot work from writing a program for the robot’s brain (i.e., the processing unit).

 

The main components of any robot are the actuators and the sensors. Actuators move a robot’s joints, providing rotary or linear motion. Servo, Stepper, and DC gearmotors are actuator brands. Sensors provide the robot’s state and environment. Examples of robot sensors include wheel encoders, ultrasonic sensors, and cameras.

 

Actuators are controlled by motor controllers and interface with a microcontroller/PLC (programmable logic controller). Some actuators are directly controlled through a PC’s USB. Sensors also interface with a microcontroller or PC.

 

Ultrasonic sensors and infrared sensor interface with a microcontroller. High-end sensors like cameras and laser scanners can interface directly with the PC. There is a power supply/battery to power all the robotic components.

 

There is an emergency stop push-­ button to stop/reset the robot’s operation. The two major parts in which to program inside a robot is a PC and a microcontroller/PLC. PLCs are mainly using in industrial robots.

 

In short, we can say robot programming is programming the PC/SBC and microcontroller/PCL inside robot for performing a specific application using actuators and feedback from various sensors. The robot applications include pick and place of the object, moving the robot from A to B.

 

A variety of programming languages can program robots. C/C++, Python, Java, C #, and so forth are used with PCs. Microcontrollers use Embedded C, the Wiring language (based on C++), which is used in Arduino, and Mbed programming (https://os.mbed.com).

 

Industrial robot applications use SCADA or vendors’ proprietary programming languages, such as ABB and KUKA. This programming is done from the industrial robot’s teach pendant. RAPID is the programming language used in ABB industrial robots to automate robotic applications.

 

Robotic programming creates intelligence in the robot for self-decision making, implementing controllers like PID to move joints, automating repeated tasks, and creating robotic vision applications.

 

Why Robot Programming Is Different

Robot Operating System (ROS)

Robot programming is a subset of computer programming. Most robots have a “brain” that can make decisions. It can be a microcontroller or a PC. The differences between robot programming and conventional programming are the input and output devices.

 

The input devices include robot sensors, teach pendants, and touch screens and the output devices include LCD displays and actuators.

 

Any of the programming languages can program robots, but good community support, performance, and prototyping time make C++ and Python the most commonly used.

The following are some of the features needed for programming a robot.

 

Threading:

As seen in the robot block diagram, there are a number of sensors and actuators in a robot. We may need a multithreaded compatible programming language in order to work with different sensors and actuators in different threads. This is called multitasking. Each thread can communicate with each other to exchange data.

 

High-level object-oriented programming:

As you already know, object-oriented programming languages are more modular and code can easily reuse. The code maintenance is also easy compared to non-object-­ oriented programming languages. These qualities create better software for robots.

 

Low-level device control:

The high-level programming languages can also access low-level devices such as GPIO (general purpose input/output) pins, Serial ports, parallel ports, USB, SPI, and I2C. Programming languages like C/C++ and Python can work with low-level devices, which is why these languages prefer single-board computers like the Raspberry Pi and Android.

 

Ease of prototyping:

The easiness in prototyping a robot algorithm is definitely a choice in the selection of programming language. Python is a good choice in prototyping robot algorithms quickly.

 

Interprocess communication:

A robot has lot of sensors and actuators. We can use multithreading architecture or write an independent program for doing each task; for example, one program takes images from a camera and detects a face, another program sends data to an embedded board. These two programs can communicate with each other to exchange data.

 

This feature creates multiple programs instead of a multithreading system. The multithreading system is more complicated than running multiple programs in parallel. Socket programming is an example of interprocess communication.

 

Performance:

If we work with high-bandwidth sensors, such as depth cameras and laser scanners, the computing resources needed to process the data is obviously high. A good programming language can only allocate appropriate computing resource without loading the computing resource. The C++ language is a good choice to handle this kind of scenario.

 

Community support:

When choosing any programming language for robot programming, make sure that there is enough community support for that language, including forums and blogs.

 

Availability of third-party libraries:

The availability of third-party libraries can make our development easy; for example, if we want to do image processing, we can use libraries like OpenCV. If your programming language has OpenCV support, it is easier to do image processing applications.

 

Existing robotics software framework support:

There are existing robotics software frameworks such as ROS to program robots. If your programming language has ROS support, it is easier to prototype a robot application.

 

Getting Started with ROS

ROS

So far, we have discussed robot programming and how it is different from another computer programming. In this section, we look at a unique software platform for programming robots: the Robot Operating System, or ROS (www.ros.org).

 

ROS is a free and open source robotics software framework that is used in both commercial and research applications. The ROS framework provides the following robot-programming capabilities.

 

Message passing interface between processes.

ROS provides a message passing interface to communicate between two programs or processes. For example, a camera processes an image and finds coordinates in the image, and then these coordinates are sent to a tracker process.

 

The tracker process does the tracking of the image by using motors. As mentioned, this is one of the features needed to program a robot. It is called interprocess communication because two processes are communicating with each other.

 

Operating system–like features.

As the name says, ROS is not a real operating system. It is a meta-operating system that provides some operating system functionalities. These functionalities include multithreading, low-level device control, package management, and hardware abstraction.

 

The hardware abstraction layer enables programmers to program a device. The advantage is that we can write code for a sensor that works the same way with different vendors. So, we don’t need to rewrite the code when we use a new sensor.

 

Package management helps users organize software in units called packages. Each package has the source code, configuration files, or data files for a specific task. These packages can be distributed and installed on other computers.

 

High-level programming language support and tools.

The advantage of ROS is that it supports popular programming languages used in robot programming, including C++, Python, and Lisp. There is experimental support for languages such as C #, Java, Node.js, and so forth. The complete list is at http://wiki.ros.org/ Client%20Libraries.

 

ROS provides client libraries for these languages, meaning the programmer can get ROS functionalities in the languages mentioned. For example, if a user wants to implement an Android application that is using ROS functionality, the rosjava client library can be used. ROS also provides tools to build robotics applications.

 

With these tools, we can build many packages with a single command. This flexibility helps programmers spend less time in creating build systems for their applications.

 

Availability of third-party libraries.

The ROS framework is integrated with the most popular third-party libraries; for example, OpenCV (https://opencv.org) is integrated for robotic vision, and PCL (http://pointclouds.org) is integrated for 3D robot perception. These libraries make ROS stronger, and the programmer can build powerful applications on top of it.

 

Off-the-shelf algorithms.

This is a useful feature. ROS has implemented popular robotics algorithms such as PID (http://wiki.ros.org/pid); SLAM (Simultaneous Localization and Mapping) (http://wiki.ros.org/ gmapping); and path planners such as A*, Dijkstra (http://wiki.ros.org/global_planner), and AMCL (Adaptive Monte Carlo Localization) (http://wiki. ros.org/amcl).

 

The list of algorithm implementations in ROS continuous. The off-the-shelf algorithms reduce development time for prototyping a robot.

 

Ease in prototyping.

One advantage of ROS is off-the-­ shelf algorithms. Along with that, ROS has packages that can be easily reused with any robot; for example, we can easily prototype our own mobile robot by customizing an existing mobile robot package available in the ROS repository.

 

We can easily reuse the ROS repository because most of the packages are open source and reusable for commercial and research purposes. So, this can reduce robot software development time.

 

Ecosystem/community support

The main reason for the popularity and development of ROS is community support. ROS developers are all over the world. They actively develop and maintain ROS packages.

 

The big community support includes developers asking questions related to ROS. ROS Answers is a platform for ROS-related queries (https://answers.ros.org/ questions/). ROS Discourse is an online forum in which ROS users discuss various topics and publish news related to ROS (https://discourse.ros.org).

 

Extensive tools and simulators.

ROS is built with many command-line and GUI tools to debug, visualize, and simulate robotics applications. These tools are very useful for working with a robot. For example, the Rviz (http://wiki.ros.org/rviz) tool is used for visualization with cameras, laser scanners, inertial measurement units, and so forth. For working with robot simulations, there are simulators such as Gazebo (http://gazebosim.org).

 

The History of ROS

ROS

The following are some ROS project historic milestones.

The ROS project started at Stanford University in 2007, led by roboticist Morgan Quigly (http://people. osrfoundation.org/morgan/). In the beginning, it was a group of software developed for robots at Stanford.

 

Later in 2007, a robotics research startup called Willow Garage (http://www.willowgarage.com/) took over the project and coined the name ROS, which stands for Robot Operating System.

  • In 2009, ROS 0.4 was released, and a working ROS robot called PR2 was developed.
  • In 2010, ROS 1.0 was released. Many of its features are still in use.
  • In 2010, ROS C Turtle was released.
  • In 2011, ROS Diamondback was released.
  • In 2011, ROS Electric Emys was released.
  • In 2012, ROS Fuerte was released.
  • In 2012, ROS Groovy Galapagos was released.
  • In 2012, the Open Source Robotics Foundation (OSRF) takes over the ROS project.
  • In 2013, ROS Hydro Medusa was released.
  • In 2014, ROS Indigo Igloo was released, this was the first long-term support (LTS) release, meaning updates and support is provided for a long period of time (typically five years).
  • In 2015, ROS Jade Turtle was released.
  • In 2016, ROS Kinetic Kame was released. It is the second LTS version of ROS.
  • In 2017, ROS Lunar Loggerhead was released.
  • In May 2018, the twelfth version of ROS, Melodic Morenia, was released.

 

The timeline of the ROS project and more detailed history is available in at www.ros.org/history/. Each version of ROS is called a ROS distribution. You may be aware of the Linux distribution, such as Ubuntu, Debian, Fedora, and so forth.

 

If you are looking for the latest ROS features, you can choose new distributions, and if you are looking for stable packages, you can choose LTS. In Figure, the recommended distribution is ROS Kinetic Kame. In this post, the examples use Kinetic Kame.

ROS is now developed and maintained by the Open Robotics, previously known as the Open Source Robotics Foundation (www.osrfoundation.org).

 

Before and After ROS

Before and After ROS

 

There was active development in robotics before the ROS project, but there was no common platform and community for developing robotics applications. Each developer created software for their own robot, which in most cases, couldn’t be reused for any other robot. Developers had to rewrite code from scratch for each robot, which takes a lot of time.

 

Also, most of the code was not actively maintained, so there was no support for the software. Also, developers needed to implement standard algorithms on their own, which took more time to prototype the robot.

 

After the ROS project, things changed. Now there is a common platform for developing robotics applications. It is a free and open source for commercial and research purposes.

 

Off-the-shelf algorithms are readily available, so there is no longer a need to code. There is big community support, which makes development easier. In short, the ROS project changed the face of robotics programming.

 

Why Use ROS?

Why Use ROS?

This is a common question that developers ask when looking for a platform to program ROS. Although ROS has many features, there are still areas in which ROS can’t be used or is not recommended to use.

 

In the case of a self-driving car, for example, we can use ROS to make a prototype, but developers do not recommend ROS to make the actual product.

 

This is due to various issues, such as security, real-time processing, and so forth. ROS may not be a good fit in some areas, but in other areas, ROS is an absolute fit.

 

In corporate robotics research centers and at universities, ROS is an ideal choice for prototyping. And ROS is used in some robotics products after a lot of fine-tuning (but not self-driving cars).

 

A project called ROS 2.0 is developing a much better version of the existing ROS in terms of security and real-time processing (https:// github.com/ros2/ros2/wiki). ROS 2.0 may become a good choice for robotics products in the future.

 

Installing ROS

Installing ROS

This is an important step in ROS development. Installing ROS on your PC is a straightforward process. Before installing, you should be aware of the various platforms that support ROS. The figure shows various operating systems on which you can install ROS. As discussed, ROS is not an operating system, but it needs a host. 

 

Ubuntu Linux is the most preferred OS for installing ROS. ROS supports Ubuntu 32-bit, 64-bit, ARM 32-bit, and ARM 64-bit. This means ROS can run on PC/desktops and on single-board computers like Raspberry Pi (http://raspberrypi.org), Android, and NVIDIA TX1/TX2. Debian Linux has good ROS support.

 

In OS X and other operating systems, ROS is still in the experimental phase, which means that ROS functionalities are not yet available.

Let’s move on to installation. If you are using a PC or an ARM board running Ubuntu armhf or arm64, you can follow the procedures at http:// wiki.ros.org/ROS/Installation. 

 

When you go to this wiki, it asks which ROS version you need to install. As mentioned, we are choosing ROS Kinetic Kame because it is LTS and stable. If you want to try the latest ROS features, use Lunar Loggerhead. After you click the distribution that you want, you get the list of operating systems that support that distribution. 

 

Choose the Ubuntu 16.04 (Xenial) operating system. When you select the operating system, you get a set of instructions. The wiki at http:// wiki.ros.org/kinetic/Installation/Ubuntu provides direct access to instructions for setting ROS in Ubuntu.

 

We can install ROS in two ways: through a binary installation or by source compilation. The first method is easy and less time-consuming. Binary installation lets you directly install ROS from prebuilt binaries. With source compilation, you create an executable by compiling ROS source code. This takes more time and is based on your PC’s specifications.

 

$ echo "source /opt/ros/kinetic/setup.bash" >> ~/.bashrc

bashrc file

 

Robots and Sensors Supporting ROS

Robots and Sensors Supporting ROS

 

The figure shows some of the popular robots that use ROS. A complete list of robots working in ROS is at http://robots.ros.org.

\ a)\ Pepper (www.ald.softbankrobotics.com/en/ robots/pepper): A service robot used for assisting people in a variety of ways.

\ b)\ REEM-C (http://pal-robotics.com/en/products/ reem-c/): A full-­size humanoid robot that is mainly used for research purposes.

\ c)\ TurtleBot 2 (www.turtlebot.com/turtlebot2/): A simple mobile robot platform that is mainly used for research and educational purposes.

\ d)\ Robonaut 2 (https://robonaut.jsc.nasa.gov/ R2/): A NASA robot designed to automate various tasks on the International Space Station.

\ e)\ Universal Robot arm: (www.universal-robots.com/products/ur5-robot): One of the popular semi-industrial robots widely used for automating various tasks in manufacturing.

 

There are also sensors supported by ROS. A complete list of these sensors is available at http://wiki.ros.org/Sensors .

\ a)\ Velodyne (http://velodynelidar.com): Popular LIDARs mainly used in self-driving cars.
\ b)\ ZED Camera (www.stereolabs.com): A popular stereo depth camera.
\ c)\ TeraRanger (www.terabee.com): A new sensor for depth sensing in 2D and 3D.
\ d)\ Xsense MTi IMU (www.xsens.com/products/): An accurate IMU solution.
\ e)\ Hokuyo Laser (www.hokuyo-aut.jp/): A popular laser scanner.
\ f)\ Intel RealSense (https://realsense.intel.com: A 3D depth sensor for robot navigation and mapping.

 

Popular ROS Computing Platforms

ros

\ a)\ NVIDIA TX1/TX2 (www.nvidia.com/en-us/ autonomous-machines/embedded-systems-­ dev-kits-modules/): Capable of running deep learning applications and computational intensive applications. The board has an ARM-based 64-bit processor that can run Ubuntu. This platform is very popular in autonomous robotics applications, especially drones.

 

\ b)\ Raspberry Pi 3 (www.raspberrypi.org/products/ raspberry-pi-3-model-b/): Very popular single-board computers for education and research. Robotics is a key area.

 

\ c)\ Intel NUC (www.intel.com/content/www/us/en/ products/boards-kits/nuc.html): Based on an x86_64 platform, which is basically a miniature version of a desktop computer.

 

\ d)\ Odroid XU4 (www.hardkernel.com/main/main.php): The Odroid series boards are similar to Raspberry Pi, but it has better configuration and performance. It is based on the ARM architecture.

 

ROS Architecture and Concepts

ROS Architecture and Concepts

We have discussed ROS, its features, and how to install it. In this section, we go deep into ROS architecture and its important concepts. Basically, ROS is a framework to communicate between two programs or process.

 

For example, if program A wants to send data to program B, and B wants to send data to program A, we can easily implement it using ROS. So the question is whether we implement it using socket programming directly. Yes, we can, but if we build more and more programs, it gets complex, so ROS is a good choice for interprocess communication.

 

 Do we really need interprocess communication in a robot? Can we program a robot without it? 

 

A robot may have many sensors and actuators, as well as a computing unit. How we can control many actuators and process so much sensor data? Can we do it in a single program? Yes, but that is not a good way of doing it.

 

The better way is, we can write independent programs to handle sensor data and controlling actuators, and often we may need to exchange data between these programs. This is the situation where we use ROS.

 

The ROS File System

ROS File System

The ROS file system includes packages, meta-packages, package manifests, repositories, message types, and services types. ROS packages are the individual units, or the atomic units, of ROS software.

 

All source code, data files, build files, dependencies, and other files are organized in packages. ROS meta package groups a set of similar packages for a specific application. AROS meta package does not have any source files or data files. It has the dependencies of similar packages. A ROS meta package organizes a set of packages.

 

package manifest is an XML file placed inside a ROS package. It has all the primary information of a ROS package, including the name of the package, description, author, dependencies, and so forth. A typical package.xml is shown next.

<?xml version="1.0"?>
<package>
<name>test_pkg</name>
<version>0.0.1</version>
<description>The test package</description>
<maintainer email="qboticslabs@gmail.com">robot</maintainer>
<license>BSD</license>
<buildtool_depend>catkin</buildtool_depend>
................. ............... .
<run_depend>catkin</run_depend>
....... . ............ .
</package>

 

ROS repository is a collection of ROS packages that share a common version control system.

 

message type description is the definition of a new ROS message type. There are existing data types available in ROS that can be directly used for our application, but if we want to create a new ROS message, we can. 

 

A new message type can be defined and stored inside the msg folder inside the package. Similar to the message type, a service type definition contains our own service definitions. It is stored in the srv folder.

 

ROS Computation Concepts

These are the terms associated with ROS computation concepts.

ROS nodesProcess that use ROS APIs to perform computations.

ROS master: An intermediate program that connects ROS nodes.

 

ROS parameter server: A program that normally runs along with the ROS master. The user can store various parameters or values on this server and all the nodes can access it. The user can set the privacy of the parameter too. If it is a public parameter, all the nodes have access; if it is private, only a specific node can access the parameter.

 

ROS topics: Named buses in which ROS nodes can send a message. A node can publish or subscribe to any number of topics.

 

ROS messageThe messages are basically going through the topic. There are existing messages based on primitive data types, and users can write their own messages.

 

ROS service: We have already seen ROS Topics, which is having publishing and subscribing mechanism. The ROS Service has a Request/Reply mechanism. A service call is a function, which can call whenever a client node sends a request. The node who create a service call is called Server node and who call the service is called client node.

 

ROS bags: A useful method to save and playback ROS topics. Also useful for logging the data from a robot to process it later.

 

ROS Command Tools

ROS Command Tools

This section discusses ROS command-line tools. What are these tools for? The tools can make our lives easier. There are different ROS tools that we can use to explore various aspects of ROS.

 

We can implement almost all the capabilities of ROS using these tools. The command-line tools are executed in the Linux terminal; like the other commands in Linux, we get the ROS command tools too.

 

The roscore command is a very important tool in ROS. When we run this command in the terminal, it starts the ROS master, the parameter server, and a logging node. We can run any other ROS program/node after running this command.

 

So run roscore on one terminal window, and use another terminal window to enter the next command to run a ROS node. If you run roscore in a terminal, you may get messages like the ones shown in Figure 

 

You can see messages in the terminal about starting the ROS master. You also see the ROS master address. The rosnode command explores all the aspects of a ROS node. For example, we can list the number of ROS nodes running on our system.

If you type any of the commands, you get complete help for the tool. The following is a common usage of rosnode.

$ rosnode list

 

The rostopic command provides information about the topics publishing/subscribing in the system. This command is very useful for listing topics, printing topic data, and publishing data.

$ rostopic list

 

If there is a topic called /chatter, we can print/echo the topic data using the following command.

$ rostopic echo /chatter

 

If we want to publish a topic with data, we can easily do this command.

$ rostopic pub topic_name msg_type data

The following is an example.

$ rostopic pub /hello std_msgs/String "Hello"

You can echo the same topic after publishing too. Note that if you run these commands in one terminal, roscore should be running.

 

The figure is the Terminator (https://launchpad.net/terminator) application in which the screen is split into separate terminal sessions. One session is running roscore. A second session is publishing a topic. A third session is echoing the same topic. The ios version command checks your ROS version.

 

The following command retrieves the current ROS version.

$ rosversion -d

Output: kinetic

The rosparam command gives a list of parameters loaded in the parameter server.

You can use the following command to list the parameters in the system.

$ rosparam list

You can get the command here.
Setting parameter
$ rosparam set parameter_name value Eg. $ rosparam set hello "Hello"
Getting a parameter
$ rosparam get parameter_name
$ rosparam get hello
Output: "Hello"

 

The roslaunch command is also useful in ROS. If you want to run more than ten ROS nodes at time, it is very difficult to launch them one by one. In this situation, we can use roslaunch files to avoid this difficulty.

 

ROS launch files are XML files in which you can insert each node that you want to run. Another advantage of the roslaunch command is that the roscore command executes with it, so we don’t need to run an additional roscore command for running the nodes.

 

The following is the syntax for running a roslaunch file. The 'roslaunch' is the command to run a launch file, along with that we have to mention package name and name of launch file.

$ roslaunch ros_pkg_name launch_file_name

roslaunch roscpp_tutorials talker_listener.launch is an example.

 

To run a ROS node, you have to use the rosrun node. Its usage is very simple.

$ rosrun ros_pkg_name node_name

rosrun roscpp_tutorials talker is an example.

ROS Demo: Hello World Example

 

This section demonstrates a basic ROS example. The example is already installed in ROS.

There are two nodes: talker and listener. The talker node publishes a string message. The listener node subscribes to it. In this example of the process, the talker publishes a Hello World message and the listener subscribes to it and prints it.

 

The figure shows a diagram of the two nodes. As discussed earlier, both nodes need to communicate with the ROS master to get the information from the other node.

 

Communication between talker and listener nodes

Let’s start the example by using the following command.

The first step in starting any node in ROS is roscore.

$ roscore

Start the talker node by using the following command in another terminal.

$ rosrun roscpp_tutorials talker

Now you see the messages printing on the terminal screen. If you list the topic by using the following command, you see a new topic called ­/chatter.

$ rostopic list

Output: /chatter

 

Now start the listener node by using the following command.

$ rosrun roscpp_tutorials listener

The subscribing begins between the two nodes

If you want to run two of the nodes together, use the roslaunch command.

$ roslaunch roscpp_tutorials talker_listener.launch

roscpp_tutorials is an existing package in ROS and talker_ listener.launch.

 

ROS Demo: turtlesim

This section demonstrates an interesting application for learning ROS concepts. The application is called turtlesim, which is a 2D simulator with a turtle in it.

You can move the turtle, read the turtle’s current position, and change the turtle’s pattern, and so forth using ROS topics, ROS services, and parameters. When working with turtlesim, you get a better idea of how to control a robot using ROS.

 

The turtlesim application is already installed on ROS. You can start this application by using the following commands.

Starting roscore

$ roscore

Starting Turtlesim application

$ rosrun turtlesim turtlesim_node

Now you can open a new terminal and list the topics by publishing the turtlesim node.

$ rostopic list

Moving the Turtle

Figure lists the services created by the turtlesim no

de. You can list the services by using the following command.

$ rosservice list
$ rosparam list

 

Moving the Turtle

If you want to move the turtle, start another ROS node by using the following command. This command has to start in another terminal.

$ rosrun turtleturtle_teleop_key

 

You can control the robot using your keyboard’s arrow keys. When you press an arrow key, it publishes velocity to /turtle1/cmd_vel, which makes the turtle move. If you want to see the back end of these nodes. It shows the topic data going to turtles.

 

Moving the Turtle in a Square

This section shows how to move the turtle along a straight path. Close all the running nodes by pressing Ctrl+C, and start a new turtle session using the following command.

Starting roscore

$ roscore

Moving the Turtle in a Square

Starting turtlenode

$ rosrun turtleturtlesim_node

Starting the node for drawing square $ rosrun turtledraw_square

The draw square in turtles

If we want to clear the turtles, we can call a service called /reset. $ rosservice call /reset This resets the turtle’s position

 

ROS GUI Tools Rviz and Rqt

Along with command-line tools, ROS has GUI tools to visualize sensor data. A popular GUI tool is Rviz. Using Rviz, we can visualize image data, 3D point clouds, and robot models, as well as transform data and so forth. This section explores the basics of the Rviz tool, which comes with the ROS installation.

 

Start Rviz using following the command.

Start roscore
$ roscore
Start rviz
$ rosrun rviz rviz

 

The following describes sections in Rviz.

3D viewportThe area to visualize the 3D data from sensors, robot transform data, 3D model data, and other kinds of 3D information.

Display panel: Displays various kinds of sensor data.

View panelOptions to view the 3D viewport according to the application.

ToolbarOptions for interacting with the 3D viewport, measuring robot position, setting the robot navigation goal, and changing the camera view.

 

Time panel: Features information about the ROS time and elapsed time. This time stamping may be useful for processing the sensor data.

Rqt: Features options to visualize 2D data, logging topics, publishing topics, calling services, and more. This is how to start the Rqt GUI.

 

Start roscore

$ roscore

Start rqt_gui

$ rosrun rqt_gui rqt_gui

You get an empty GUI with some menus. You can add your own plug-ins from the drop-down menu. Figure is a screenshot of rqt_gui loaded with a plug-in.

 

Programming with ROS

 Programming with ROS

Creating basic ROS nodes to move the TurtleBot in the simulation. Afterward, you learn how to interface and program an Arduino and Tiva-C Launchpad using ROS. These tutorials are very useful for when we create our own robot.

 

At the end of the post, you see how to set up ROS and program it in the Raspberry Pi 3. To implement a new ROS topic, or a new ROS message, or a ROS service, we can simply call these ROS built-in functions to create it.

 

We don’t need to implement ROS features from scratch. The programs that use ROS built-­ in functions/APIs (application program interface) are called ROS nodes.

 

In this post, we create ROS nodes for different applications. The ROS wiki provides extensive documentation on creating ROS nodes. As a beginner, it may be difficult to understand most of the topics mentioned on the ROS wiki. This post gives you a brief look at them to get started with ROS programming.

 

There are some steps that we need to take before proceeding to ROS programming. The first step is to create a ROS workspace. The next section discusses the ROS workspace and how to create it.

 

Creating a ROS Workspace and Package

 

The command to build the catkin workspace is catkin_make.

$ ~/catkin_ws$ catkin_make

You get the following output after entering this command.

 

Now you can see a few folders in addition to the class='lazy' data-src folder. More information about the building process is in the next section. The class='lazy' data-src folder is where our packages are kept. If you want to create or build a package, you have to copy those packages to the class='lazy' data-src folder. After creating the workspace, it is an important thing to add the workspace environment.

 

This means you have to set the workspace path so that the packages inside the workspace become accessible and visible. To do this, you have to do the following steps.

 

Open the .bashrc file in the home folder and add the following line at the end of the file.

At a terminal, switch to the home folder and select the .bashrc file.

$ gedit .bashrc

Add the following line at the end of .bashrc.

source ~/catkin_ws/devel/setup.bash

 

As you already know, the .bashrc script in the home folder executes when a new terminal session starts. So, the command inserted in the .bashrc file also executes.

setup.bash in the following command has variables to add to the Linux environment.

source ~/catkin_ws/devel/setup.bash

catkin_make output

When we source this file, the workspace path is added in the current terminal session. Now when we use any terminal, we can access the packages inside this workspace.

 

Before discussing the creation of packages, we need to discuss the catkin build system in ROS. You get a better idea of the building process when you are aware of the catkin build system.

 

ROS Build System

ROS Build System

 

Using ROS Client Libraries

We have covered various ROS concepts like topics, services, messages, and so forth. How do we implement these concepts? The answer is by using ROS client libraries.

 

The ROS client libraries are a collection of code with functions to implement ROS concepts. We can simply include these library functions in our code to make it a ROS node. The client library saves development time because it provides the built-in functions to make a ROS application.

 

We can write ROS nodes in any programming language. If there is any ROS client for that programming language, it is easier to create ROS nodes; otherwise, we may need to implement our own ROS concepts.

 

The following are the main ROS client libraries.

roscpp: This is the ROS client library for C++. It is widely used for developing ROS applications because of its high performance.

 

rospy: This is the ROS client library for Python (http:// wiki.ros.org/rospy). Its advantage is saving development time. We can create a ROS node in less time than with roscpp.

 

It is ideal for quick prototyping applications, but performance is weaker than with roscpp. Most of the command line tools in ROS are coded using rospy such as roslaunch, roscore and so forth.

 

roslisp: This is the ROS client library of the Lisp language. It is mainly used in motion planning libraries on ROS, but it is not as popular as roscpp and rospy.

There are also experimental client libraries, including rosjava, rosnodejs, and roslua. The complete list of ROS client libraries is at http://wiki.ros.org/Client%20Libraries.

We will mainly work with roscpp and rospy. The next section shows a basic example of ROS nodes created using roscpp and rospy.

 

roscpp and raspy

This section discusses the various aspects of writing a node using client libraries such as roscpp and rospy. This includes the header files and modules used in ROS nodes, initializing a ROS node, publishing and subscribing a topic, and so forth.

 

Header Files and ROS Modules

When you write code in C++, the first section includes the header files. Similarly, when you write Python code, the first section imports Python modules. In this section, we look at the important headers files and modules that we need to import into a ROS node.

  • To create a ROS C++ node, we have to include the following header files. #include "ros/ros.h"
  • The ros.h has all the headers required to implement ROS functionalities.
  • We can’t create a ROS node without including this header file.

 

The next type of header file used in ROS nodes is a ROS message header. If we want to use a specific message type in our node, we have to include the message header file. ROS has some built-in message definition, and the user can also create a new message definition.

 

There is a built-in message package in ROS called std_msgs that has a message definition of standard data types, such as int, float, string, and so forth. For example, if we want to include a strong message in our code, we can use the following line of code.

 

#include "std_msgs/String.h"

Here, the first part is the package name and the next part is the message type name. If there is a custom message type, we can call it with the following syntax.

# include "msg_pkg_name/message_name.h"


The following are some of the messages in the std_msgs package.

#include "std_msgs/Int32.h"

#include "std_msgs/Int64.h"

 

The complete list of message types inside the std_msgs package is at http://wiki.ros.org/std_msgs.

 

In Python, we have to import modules to create a ROS node. The ROS module that we need to import is imported rospy, rospy has all the important ROS functions. To import a message type, we have to import the specific modules, like we did in C++.

The following is an example of importing a string message type in Python.

from std_msgs.msg import String

We have to use package_name.msg and import the required message type.

 

Initializing a ROS Node

Before starting any ROS node, the first function called initializes the node. This is a mandatory step in any ROS node.

In C++, we initialize using the following line of code.

int main(int argc, char **argv)

{

ros::init(argc, argv, "name_of_node")

.....................

}

 

After the int main() function, we have to include ros::init(), which initializes the ROS node. We can pass the argc,argv command-line arguments to the init() function and the name of the node. This is the ROS node name, and we can retrieve its list by using rosnode list.

In Python, we use the following line of code.

rospy.init_node('name_of_node', anonymous=True);

The first argument is the name of the node, and the second argument is anonymous=True, which means the node can run on multiple instances.

 

Printing Messages in a ROS Node

ROS provides APIs to log messages. These messages are a readable string that conveys the status of the node. In C++, the following functions log the node’s messages.

ROS_INFO(string_msg,args):Logging the information of node ROS_WARN(string_msg,args):Logging warning of the node ROS_DEBUG(string_msg,args):Logging debug messages ROS_ERROR(string_msg,args):Logging error messages ROS_FATAL(string_msg,args):Logging Fatal messages Eg:ROS_DEBUG("Hello %s","World");

 

In Python, there are different functions for the logging operations.

rospy.logdebug(msg, *args)

rospy.logerr(msg, *args)
rospy.logfatal(msg, *args)
rospy.loginfo(msg, *args)
rospy.logwarn(msg, *args)
Creating a Node Handle

 

After initializing the node, we have to create a NodeHandle instance that starts the ROS node and other operations, like publishing/subscribing a topic. We are using the ros:: NodeHandle instance to create those operations.

In C++, the following shows how to create an instance of ros:: NodeHandle.

ros::NodeHandle nh;

The rest of the operations in the node use the nh instance. In Python, we don’t need to create a handle; the rospy module internally handles it.

 

Creating a ROS Message Definition

Before publishing a topic, we have to create a ROS message definition. The message definition is created by using the following methods. In C++, we can create an instance of a ROS message with the following line of code; for example, this is how we create an instance of std_msgs/ String.

std_msgs::String msg;

After creating the instance of the ROS message, we can add the data by using the following line of code.

msg.data = "String data"

 

In Python, we use the following line of code to add data to the string message.

msg = String()

msg.data = "string data"

Publishing a Topic in ROS Node

 

This section shows how to publish a topic in a ROS node.

In C++, we use the following syntax.

ros::Publisher publisher_object = node_handle.advertise<ROS message type >("topic_name",1000)

After creating the publisher object, the publish() command sends the ROS message through the topic.

publisher_object.publish(message)

 

Example:

ros::Publisher chatter_pub = nh.advertise<std_ msgs::String>("chatter", 1000);

chatter_pub.publish(msg);

In this example, chatter_pub is the ROS publisher instance, and it is going to publish a topic with message type std_msgs/String and chatter as the topic name. The queue size is 1000.

 

In Python, the publishing syntax is as follows.

Syntax: publisher_instance = rospy.Publisher('topic_name', message_ type, queue_size)

Example:

pub = rospy.Publisher('chatter', String, queue_size=10)

pub.publish(hello_str)

This example publishes a topic called chatter with a std_msgs/String message type and a queue_size of 10.

 

The ROS Sleep Function in ROS Node

If we want to make a constant rate inside a loop that is inside a node, we can use ros::Rate. We can create an instance of ros::Rate and mention the desired rate that we want. After creating the instance, we have to call the sleep() function inside it to get the rate in effect.

 

The following is an example of getting 10 Hz in C++.

ros::Rate r(10); // 10 hz

r.sleep();
The following is how to do it in Python.
rate = rospy.Rate(10) # 10hz
rate.sleep()
Setting and Getting a ROS Parameter
In C++, we use the following line of code to access a parameter in our code. Basically, we have to declare a variable and use the getParam() function inside the node_handle to access the desired parameter.
std::string global_name;
if (nh.getParam("/global_name", global_name))
{
...
}
The following shows how to set a ROS parameter. The name and the value should be mentioned inside the setParam() function.
nh.setParam("/global_param", 5);
In Python, we can do the same thing using the following line of code.
global_name = rospy.get_param("/global_name")
rospy.set_param('~private_int', '2')

 

The Hello World Example Using ROS

In this section, you are going to create a basic package called hello_world, and a publisher node and a subscriber node to send a “Hello World” string message. You also learn how to write a node in C++ and Python.

 

Creating a hello_world Package

In ROS, the programs organized as packages. So we have to create a ROS package before writing any program. To create a ROS package, we have to give a name of the package, then the dependent packages which help to compile the programs inside the package.

 

For example, if your package has a C++ program, you have to add 'roscpp' as dependency and if it is python, you have to add 'rospy' as a dependency.

 

Before creating the package, first, switch to the class='lazy' data-src folder.

$ catkin_ws/class='lazy' data-src$ catkin_create_pkg hello_world roscpp rospy std_msgs

 

Now we can explore the different files created. The first important file is package.xml. As discussed, this file has information about the package and its dependencies. The package.xml file definition. Actually, when we create the package, it also has some commented code. All comments have been removed here to make it cleaner.

 

You can edit this file and add dependencies, package information, and other information to the package. You can learn more about package.xml at http://wiki.ros.org/catkin/package.xml.

hello

In this file, the minimum version of CMake required to build the package and the project name is at the top of the file.

 

The find_package() finds the necessary dependencies of this package. If these packages are not available, we can’t able to build this package. The catkin_package() is a catkin-provide CMake macro used for specifying catkin-specific information to the build system.

 

You can learn more about CMakeLists.txt at http://wiki.ros.org/ catkin/CMakeLists.txt. 

A good reference for creating a ROS package is at http://wiki.ros.org/ROS/Tutorials/catkin/CreatingPackage.

 

Creating a ROS C++ Node

After creating the package, the next step is to create the ROS nodes. The C++ code is kept in the class='lazy' data-src folder. The following is the first ROS node. It’s a C++ node to publish a “Hello World” string message. You can save it under class='lazy' data-src/talker.cpp.

#include "ros/ros.h"

#include "std_msgs/String.h"
#include <sstream>
int main(int argc, char **argv)
{
ros::init(argc, argv, "talker"); ros::NodeHandle n;
ros::Publisher chatter_pub = n.advertise<std_ msgs::String>("chatter", 1000);
ros::Rate loop_rate(10);
int count = 0;
while (ros::ok())
{
std_msgs::String msg;
std::stringstream ss;
ss
<< "hello world " << count; msg.data = ss.str(); ROS_INFO("%s", msg.data.c_str()); chatter_pub.publish(msg); ros::spinOnce()
loop_rate.sleep();
++count;
}
return 0;
}

 

The code is self-explanatory. Basically, it creates a new string message instance and a publisher instance. After creating both, it adds data to the string message along with a count. After adding the data, it publishes the topic, "/chatter. You can also see the usage of the ros::spinOnce() function here. The code executes until you press Ctrl+C.

 

Next, you see the listener.cpp, which subscribes the topic published by talker.cpp. After getting data from the topic, it prints that message.

#include "ros/ros.h"
#include "std_msgs/String.h"
void chatterCallback(const std_msgs::String::ConstPtr& msg) {
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
int main(int argc, char **argv)
{
ros::init(argc, argv, "listener");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
ros::spin();
return 0;
}

 

In listener.cpp, the "chatter" topic is subscribing and registering a callback function for the topic, which is chatterCallback. The callback is defined at the beginning of the code. Whenever a message comes to the "chatter" topic, this callback is executed. Inside the callback, the data in the message is printed.

ros::spin() executes the subscribe callbacks and helps the node remain in a wait state, so it won’t quit until you press Ctrl+C.

Editing the CMakeLists.txt File

After saving the two files in the hello_world/class='lazy' data-src folder, the nodes need to be compiled to create the executable. 

To do this, we have to edit the CMakeLists.txt file, which is not too complicated.

 

We need to add four lines of code to CMakeLists.txt. The figure shows the additional lines of code to insert.

 

You can see that we are adding add_executable() and target_ link_libraries() to CMakeLists.txt. add_executable() creates the executable from the source code. The first parameter is the executable name, which links with the libraries. If these two processes are successful, we get executable nodes.

 

Building C++ Nodes

After saving CMakeLists.txt, we can build the source code. The command to build the nodes is catkin_make. Just switch to the workspace folder and execute the catkin_make command. To switch to the catkin_ws folder, assume that the workspace is in the home folder.

$ cd ~/catkin_ws

 

Executing the catkin_make command to build the nodes $ catkin_make

If everything is correct, you get a message saying that the build was successful. So we have successfully built the nodes. Now what? We can execute these nodes, right? That is covered in the next section.

 

Executing C++ Nodes

  • After building the nodes, the executables are generated inside the catkin_ ws/devel/lib/hello_world/ folder.
  • After creating the executable, we can run it on a Linux terminal.
  • Open three terminals, and execute each command one by one.
Starting roscore

$ roscore

The following command starts the talker node. We can use the rosrun command to start the node.

$ rosrun hello_world talker

The node prints messages on the terminal. Check the list of ROS topics in the system by using the following command.

$ rostopic list

 

You see the following topics.

/chatter

/rosout

/rosout_agg

'chatter is the topic published by the talker node. The /rosout topics are for logging purposes. It starts publishing when we execute the roscore command.

The listener node can start in another terminal.

$ rosrun hello_world listener

 

You can close each terminal by pressing the Ctrl+C key combination. Next, we look at the talker and listener nodes in Python.

 

Creating Python Nodes

We can make a folder called script inside the package, and we can keep the Python scripts inside this folder (scripts/talker.py). The first program that we are going to discuss is http://talker.py.

import rospy
from std_msgs.msg import String
def talker():
rospy.init_node('talker', anonymous=True)
pub = rospy.Publisher('chatter', String, queue_size=10) rate = rospy.Rate(10) # 10hz
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass

 

In the http://talker.py code, in the beginning, we can see, we are importing the rospy module and ros message modules. In the talker() function, we can see the initialization of ROS node, the creation of a new ROS publisher.

 

After initializing the node, we are using a while loop to publish a string message called “Hello World” to the /chatter topic. The working of this node is same as talker.cpp that we already discussed.

 

The subscribing node, called http://listener.py, should be kept inside scripts/ http://listener.py.

import rospy

from std_msgs.msg import String
def callback(data):
rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
def listener():
#In ROS, nodes are uniquely named. If two nodes with the same
#node are launched, the previous one is kicked off. The
#anonymous=True flag means that rospy will choose a unique
#name for our 'talker' node so that multiple talkers can
#run simultaneously.
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("chatter", String, callback)
#spin() simply keeps python from exiting until this node is stopped
rospy.spin()
if __name__ == '__main__':
listener()

The node is similar to listener.cpp. We are initializing the node and creating a subscriber on the /chatter topic. After subscribing the topic, it waits for ROS messages. The waiting is done with the rospy.spin() function. Inside the callback() function, the message is printed.

 

Executing Python Nodes

Executing Python Nodes

In this section, we see how to execute the nodes. There is no need to compile the Python nodes. We can just execute it using the following commands. You can see the output of the commands.

Start the roscore

$ roscore
Start the http://talker.py
$ rosrun hello_world http://talker.py
Start the http://listener.py
$ rosrun hello_world http://listener.py

 

Creating Launch Files

This section discusses how to write launch files for C++ and Python nodes. The advantage of ROS launch files is that we can run any number of nodes in a single command. We can create a folder called launch inside the package and keep the launch files in that folder.

 

The following is talker_listener.launch, which can run C++ executables.

<launch>
<node name="listener_node" pkg="hello_world" type="listener" output="screen"/>
<node name="talker_node" pkg="hello_world" type="talker" output="screen"/>
</launch>

 

lunch file

 

Visualizing a Computing Graph

In the graph, you see talker_node, which is the name given to talker in the launch file. listener_node is the name of the listener node. /chatter is the topic published by the talker_node. It is subscribed by the listener_node.

 

All the debug messages from these two nodes are going to /rosout. The debug messages are a message that we printed using ROS debug functions (http://wiki.ros.org/roscpp/Over view/Logging). We have already discussed those functions. The /rqt_gui node is also sending debug statements to /rosout.

 

This is how the ROS computation graph works.

Programming turtle using rospy

We are done with the “Hello World” ROS example in C++ and Python. In this section, we use a more interesting application. We saw the turtle application in ROS. Now we look at how to program turtle using rospy Py. We are using rospy for the demo because it is very simple to prototype. In turtles, there is a turtle that we can move around the workspace.

 

Moving turtles

This section discusses how to program the turtle to move around its workspace. You already know how to start the turtle application. The following is the list of commands to run.

Starting roscore

$ roscore
Running turtlesim node in another terminal
$ rosrun turtlesim turtlesim_node
Here is the list of topics which is publishing by turtlesim_node
$ rostopic list
/rosout
/rosout_agg
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose

 

To move the turtle inside the turtle application, publish the linear and angular velocity to the /turtle1/cmd_vel topic.

Check the type of the /turtle1/cmd_vel topic by using the following command.
$ rostopic type /turtle1/cmd_vel

geometry_msgs/Twist

This means that the /cmd_vel topic has the geometry_msgs/Twist message type, so we have to publish the same message type to this topic to move the robot. To see the geometry_msgs/Twist definition, use the following command.$ rosmsg show geometry_msgs/Twist

turtle

The twist message has two subsections: linear velocity and angular velocity.

 

If we set the robot’s linear velocity component, it moves forward or backward. In turtles, we can only set the linear.x component because it can move only in the x-direction; there is no motion along y and z. Also, we can set angular.z components to rotate the robot on its axis.

 

There is no effect on other components.

More information about this message is at http://docs.ros.org/api/ geometry_msgs/html/msg/Twist.html.

 

How can we move the topic through the command line? By using rostopic. The following command publishes the linear.x = 0.1 velocity to the turtlenode.

 

Note You don’t need to enter the complete command. Use the Tab key to autocomplete the command. Just type rostopic pub /turtle1/ cmd_vel, and use the Tab key to autocomplete other fields.

$ rostopic pub /turtle1/cmd_vel geometry_msgs/Twist "linear:
x:0.1
y:0
z:0
angular:
x:0
y:0
z:0"

 

How do we move the turtle in a Python node?

We are going to create a new node called move_turtle and publish a twisted message to the turtlenode. The figure shows the communication between the two nodes. The following is the code for the move_turtle.py node. You can read the comments in the code to get a better idea about each line of code.

 

#!/usr/bin/env python

import rospy
#Importing Twist message: Used to send velocity to turtlefrom geometry_msgs.msg import Twist
#Handling command line arguments import sys
#Function to move turtle: Linear and angular velocities are arguments
def move_turtle(lin_vel,ang_vel):
rospy.init_node('move_turtle', anonymous=False)
#The /turtle1/cmd_vel is the topic in which we have to send Twist messages
pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10) rate = rospy.Rate(10) # 10hz
#Creating Twist message instance vel = Twist()
while not rospy.is_shutdown():
#Adding linear and angular velocity to the message
vel.linear.x = lin_vel
vel.linear.y = 0
vel.linear.z = 0
vel.angular.x = 0
vel.angular.y = 0
vel.angular.z = ang_vel
rospy.loginfo("Linear Vel = %f: Angular Vel = %f",lin_vel,ang_vel)
#Publishing Twist message
pub.publish(vel)
rate.sleep()
if __name__ == '__main__':
try:
#Providing linear and angular velocity through command line move_turtle(float(sys.argv[1]),float(sys.argv[2]))
except rospy.ROSInterruptException:
pass

 

This code takes the linear and the angular velocity through a command line. We can use the Python sys module to get the command-line arguments inside our code. Once it has the linear velocity and the angular velocity, it calls the move_turtle() function, which inserts both velocities into a twisted message and publishes it.

 

You can save the code as move_turtle.py, and change the permission to executable.

The following shows how to run it.

Start roscore

$ roscore

Start the turtlenode

$ rosrun turtleturtlesim_node

Run the move_turtle.py node along with the command-line arguments, which are 0.2 and 0.1. That is, linear velocity = 0.2 m/s and angular velocity = 0.1 rad/s.

$ rosrun hello_world move_turtle.py 0.2 0.1

 

Printing the Robot’s Position

Printing the Robot’s Position

You have seen how to publish the turtle’s velocity. Now you are going to learn how to get the turtle’s current position from the /turtle1/pose topic. 

Restart turtlesim_node and close move_turtle.py. Echo the /turtle1/ pose topic using rostopic. $ rostopic echo /turtle1/pose

You see the current (x,y, theta) value of the robot and the turtle’s current linear and angular velocities.

 

If you want to get this position in a Python node, you have to subscribe to the called /turtle1/pose topic. To do that and get the data from the message, you have to know the ROS message type. The following finds the message type.

$ rostopic type /turtle1/pose

turtlsim/Pose

If you want to know the message definition, use the following command. $ rosmsg show turtles/Pose

 

As shown in Figure, there are five terms inside the message: x, y, theta, linear velocity, and angular velocity.

To learn more about this message, refer to http://docs.ros.org/api/ turtlesim/html/msg/Pose.html.

 

Let’s modify the existing move_turtle.py and add the option to subscribe to the /turtle1/pose topic. Save this code as move_turtle_get_pose.py. The figure shows how the program works. It is feeding velocity and subscribing the position from the turtlenode at the same time.

move_turtle_get_pose.py code

#!/usr/bin/env python
import rospy
from geometry_msgs.msg import Twist
from turtlesim.msg import Pose
import sys
#/turtle1/Pose topic callback
def pose_callback(pose):
rospy.loginfo("Robot X = %f : Y=%f :
Z=%f\n",pose.x,pose.y,pose.theta)
def move_turtle(lin_vel,ang_vel):
rospy.init_node('move_turtle', anonymous=True)
pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
#Creating new subscriber: Topic name= /turtle1/pose:
Callback name: pose_callback rospy.Subscriber('/turtle1/pose',Pose, pose_callback)
rate = rospy.Rate(10) # 10hz
vel = Twist()
while not rospy.is_shutdown():
vel.linear.x = lin_vel
vel.linear.y = 0
vel.linear.z = 0
vel.angular.x = 0
vel.angular.y = 0
vel.angular.z = ang_vel
rospy.loginfo("Linear Vel = %f: Angular Vel = %f",lin_ vel,ang_vel)
pub.publish(vel)
rate.sleep()
if __name__ == '__main__':
try:
move_turtle(float(sys.argv[1]),float(sys.argv[2]))
except rospy.ROSInterruptException:
pass

 

This code is self-explanatory. You can see comments where the code for subscribing the /turtle1/pose topic is added. Run the code by using the following commands. 

 

Starting roscore

$ roscore
Restarting the turtlesim node
$ rosrun turtlesim turtlesim_node
Running move_turtle_get_pose.py code
$ rosrun hello_world move_turtle_get_pose.py 0.2 0.1

 

If we are getting both position and velocity, we can simply command the robot to move to a specific distance, right? The next example is moving the robot with distance feedback. The code is a modification of the move_turtle_get_pose.py code. Moving the Robot with Position Feedback We can save this code as move_distance.py. 

 

Communication of move_distance.py to turtles

This node is simple. We can give linear velocity, angular velocity, and distance (global distance) to it as a command-line argument.

 

Along with publishing velocity to the turtle, it checks the distance moved. When it reaches its destination, the turtle or robot stops. You can read the comments inside the code to understand what's happening inside the code.

#!/usr/bin/env python

import rospy
from geometry_msgs.msg import Twist
from turtlesim.msg import Pose
import sys
robot_x = 0
def pose_callback(pose):
global robot_x
rospy.loginfo("Robot X = %f\n",pose.x)
robot_x = pose.x
def move_turtle(lin_vel,ang_vel,distance):
global robot_x
rospy.init_node('move_turtle', anonymous=True)
pub = rospy.Publisher('/turtle1/cmd_vel', Twist, queue_size=10)
rospy.Subscriber('/turtle1/pose',Pose, pose_callback)
rate = rospy.Rate(10) # 10hz
vel = Twist()
while not rospy.is_shutdown():
vel.linear.x = lin_vel
vel.linear.y = 0
vel.linear.z = 0
vel.angular.x = 0
vel.angular.y = 0
vel.angular.z = ang_vel
#rospy.loginfo("Linear Vel = %f: Angular Vel = %f", lin_vel,ang_vel)
#Checking the robot distance is greater than the commanded distance
# If it is greater, stop the node
if(robot_x >= distance):
rospy.loginfo("Robot Reached destination")
rospy.logwarn("Stopping robot")
break
pub.publish(vel)
rate.sleep()
if __name__ == '__main__':
try:
move_turtle(float(sys.argv[1]),float(sys.argv[2]), float(sys.argv[3]))
except rospy.ROSInterruptException:
pass
We can run the code by using the following commands. You can Figure 5-25 for seeing the output
Start roscore
$ roscore
Start turtlenode
$ rosrun turtleturtlesim_node
Run the move_distance.py. Mention linear, angular velocity and the global distance the robot should travel.
$ rosrun hello_world move_distance.py 0.2 0.0 8.0

 

The output of move_distance.py

We have played with a lot of things in turtle using ROS topic. Now, we can work with ROS service and a ROS parameter. The next example simply resets the turtle workspace, and randomly changes the background color.

 

The workspace reset is accomplished using ROS services, and the color changing is done using the ROS parameter. When the workspace resets, the robot’s position resets to the home position and the turtle model changes.

 

The following code sets the parameter for the background color and resets the workspace by calling /reset service.

#!/usr/bin/env python

import rospy
import random
from std_srvs.srv import Empty
def change_color():
rospy.init_node('change_color', anonymous=True)
#Setting random values from 0-255 in the color parameters rospy.set_param('/background_b',random.randint(0,255)) rospy.set_param('/background_g',random.randint(0,255)) rospy.set_param('/background_r',random.randint(0,255))
#Waiting for service /reset rospy.wait_for_service('/reset')
#Calling /reset service
try:
serv = rospy.ServiceProxy('/reset',Empty)
resp = serv()
rospy.loginfo("Executed service")
except rospy.ServiceException, e:
rospy.loginfo("Service call failed: %s" %e)
rospy.spin()
if __name__ == '__main__':
try:
change_color()
except rospy.ROSInterruptException:
pass
We can save the code as turtle_service_param.py. The following commands starts the ROS node (see Figure 5-29).
Starting roscore
$ roscore
Starting turtlesim_node
$ rosrun turtlesim turtlesim_node
Execute the turtle_service_param.py code
$ rosrun hello_world turtle_service_param.py

 

You have successfully done the turtle exercise. The turtle is actually a robot. You can do all of the operations that you did with the turtle with a physical robot too. The next section explains how to do this operation with an actual robot. It is only a simulation but uses the same procedure as with real hardware.

 

Programming TurtleBot Simulation Using rospy

Launching the TurtleBot Simulation

After installing the TurtleBot packages, launch the simulation of TurtleBot 2 by using the following command.

 

Note It may take time to load the environment in Gazebo. Initially, the Gazebo window may be black because some 3D mesh files are downloading. The time it takes to complete the download depends on your Internet speed. If you feel that Gazebo is stuck, just cancel by pressing Ctrl+C, and launch it again.

 

$ roslaunch turtlebot_gazebo turtlebot_world.launch

This command launches a ROS launch file from the turtlebot_gazebo package. If the simulation loads successfully, you get a window like the one shown in Figure.

 

If you want to move the robot around the environment, start a new terminal and launch the following command.

$ roslaunch turtlebot_teleop keyboard_teleop.launch

When you run this command, you get the following messages on the terminal. Click the terminal using a mouse, and press the keys mentioned on the terminal. You can move the robot using I, J, and L keys.

 

turtle

If you want to stop the robot, press Space bar, if you want to stop the simulation or teleoperation, just press Ctrl+C.

 

Moving a Fixed Distance Using a Python Node

In this section, we move the robot to a fixed distance using the node that we used for turtlesim. We can modify the move_distance.py node.

For turtlebot the velocity Twist message topic is: /cmd_vel_
mux/input/teleop: Message type: geometry_msgs/Twist
Robot position feedback topic: /odom : Message type: nav_msgs/ Odometry

 

We get the definition of odometry from the following command.

$ rosmsg show nav_msgs/Odometry

It is a built-in message type in ROS. We have to import the modules for these messages. The logic of the robot movement is the same as in turtlesim. The distance is global distance. The initial origin of the robot is 0,0,0.

#!/usr/bin/env python
import rospy
from geometry_msgs.msg import Twist
from nav_msgs.msg import Odometry
import sys
robot_x = 0
def pose_callback(msg):
global robot_x
#Reading x position from the Odometry message robot_x = msg.pose.pose.position.x
rospy.loginfo("Robot X = %f\n",robot_x)
def move_turtle(lin_vel,ang_vel,distance):
global robot_x
rospy.init_node('move_turtlebot', anonymous=False)
#The Twist topic is /cmd_vel_muc/input/teleop
pub = rospy.Publisher('/cmd_vel_mux/input/teleop', Twist, queue_size=10)
#Position topic is /odom
rospy.Subscriber('/odom',Odometry, pose_callback)
rate = rospy.Rate(10) # 10hz
vel = Twist()
while not rospy.is_shutdown():
vel.linear.x = lin_vel
vel.linear.y = 0
vel.linear.z = 0
vel.angular.x = 0
vel.angular.y = 0
vel.angular.z = ang_vel
#rospy.loginfo("Linear Vel = %f: Angular Vel = %f",lin_ vel,ang_vel)
if(robot_x >= distance):
rospy.loginfo("Robot Reached destination")
rospy.logwarn("Stopping robot")
break
pub.publish(vel)
rate.sleep()
if __name__ == '__main__':
try:
move_turtle(float(sys.argv[1]),float(sys.
argv[2]),float(sys.argv[3]))
except rospy.ROSInterruptException:
pass

 

We can run this code by using the following command.

$ roslaunch turtlebot_gazebo turtlebot_world.launch

Start the TurtleBot simulation. If you are launching a file, you don’t need to start roscore because roslaunch already runs roscore.

Run the move distance node with command-line arguments.

$ rosrun hello_world move_turtlebot.py 0.2 0 3

 

Finding Obstacles

Using the same logic, we can find obstacles around TurtleBot. You can subscribe to the laser scan topic from TurtleBot, which gives the obstacle range around the robot.

Topic: /scan

Message Type: sensor_msgs/LaserScan

Also, you get all the fields inside this message by using the following command.

$ rosmsg show sensor_msgs/LaserScan

 

A good exercise is to create an obstacle avoidance application in ROS.

Microcontrollers are used for various applications. In robotics, controllers are used to interface sensors, such as ultrasonic distance sensors, IR sensors, and so forth, and for adjusting the speed of a robot’s motors. Microcontrollers can also communicate with a PC via serial communication.

 

In this section, you look at some basic interfacing with popular microcontroller platforms, such as the Arduino (www.arduino.cc) and the Tiva-C Launchpad, and with single-­ board computers, such as Raspberry Pi 3 board (www.raspberrypi.org).

Let’s start with the Arduino board.

 

Interfacing Arduino with ROS

arduino

 

Installing ROS on a Raspberry Pi

The Raspberry Pi computer is a popular board for DIY projects and robotics. The cost of the board is low, and its specifications are best for DIY projects. The latest Raspberry Pi 3 board has the following specs.

Name of SoC: Broadcom BCM2837.
CPU: 4× ARM Cortex-A53, 1.2GHz.
GPU: Broadcom VideoCore IV.
RAM: 1GB LPDDR2 (900 MHz)
Networking: 10/100 Ethernet, 2.4GHz 802.11n wireless.
Bluetooth: Bluetooth 4.1 Classic, Bluetooth Low Energy.
Storage: microSD.
GPIO: 40-pin header, populated.

So how do you install an OS on this board and then install ROS onto it? 

 

Booting to Ubuntu

After plugging in the SD card, plug a 5V, 2A supply to the Raspberry Pi 3, and connect Pi to an HDMI monitor. Also, connect a keyboard and a mouse via USB. The system boots up, and you see the Ubuntu Mate desktop.

 

Installing ROS on a Raspberry Pi

You can follow the ROS installation instructions at http://wiki.ros.org/ kinetic/Installation/Ubuntu. These instructions are the same for the armhf platform, so it works well in Raspberry Pi 3.

 

Summary

This post discussed programming with ROS. We started the post by discussing creating a ROS workspace. We saw how to create a workspace and how to create a ROS package. After creating a package, we saw how to write ROS nodes using C++ and Python. We wrote a sample ROS node using C++ and Python.

 

We discussed ROS launch files and how to include our nodes in a launch file. We created a set of examples to work with turtles in ROS, and we worked with a Gazebo simulation of TurtleBot.

 

At the end of the post, we saw how to program embedded boards such as the Arduino and the Raspberry Pi using ROS, which is very useful when creating robots.

Recommend