ROS

ROS stands for Robot Operating System. It is a collection of libraries and utilities that make up a software framework that is a node based publisher-subscriber model. It allows developers to quickly write modular code for a robot that does a specifc task while providing a layer of useful libraries and introspection tools. The publisher-subscriber principal allows for minimal coupling by leaving it up to each node to subscribe and publish data as it wishes to a common bus that is accessible to all other nodes.

The following are a set of notes I have taken while learning how to use ROS, and applying ROS to build an autonomous street robot name Primo.

Official ROS package page.

A package in ROS is the “software organization unit of ROS code”. Think of a package as software project that does one task. It might contain multiple nodes, aka executable ROS processes, and a bunch of configuration information.

For example, say we have a robot with a robotic arm that uses a motor that is connected to an output shaft via some gearing, and also cause we're fancy we have a torque transducers on the output shaft along with an encoder for position information. That is a good amount of stuff for just one arm joint, but this “arm joint stuff” perfect candidate for a package. We can boil it down to set of tasks relating to the joint and cease a package. On top of that we can create the package in such a way that it can be configurable, and applied to more of the similar joints. The package would be responsible for the following:

Sketch of package responsibilities

  • Take in commands to control the joint in different ways
    • Position control to send the joint in a specific place
    • Force control to push against something or grip with a set force
    • Velocity control for a spinning joint such as a screwing task
  • Make sure the joint obeys within its limits of force, torque, velocity and position
  • Hold a set of configuration data such as position of the joint, name, etc
  • Have a driver interface to the motor controller which could be a serial, or CAN connection
  • Monitor any fault conditions and have a mechanism in place for what to do when bad things happen.

With that sketch of responsibilities we can create engineering requirements that fully define the tasks and then go on to either try to find a package that does this already, or make our own. If we decide to make our own we'll build out our package and have nodes that handle each of those tasks that can easily talk to each other etc. Hope that gives you a good idea of what a ROS package is!

Nodes: A node is an executable that uses ROS to communicate with other nodes. Messages: ROS data type used when subscribing or publishing to a topic. Topics: Nodes can publish messages to a topic as well as subscribe to a topic to receive messages. Master: Name service for ROS (i.e. helps nodes find each other) rosout: ROS equivalent of stdout/stderr roscore: Master + rosout + parameter server (parameter server will be introduced later)

Use the rosnode command to get information about currently running nodes.

The following is the simplest structure of a ROS package:

my_package/
    CMakeLists.txt
    package.xml

The manifest is a file called package.xml and is a description of the package.

A package in a catkin workspace looks like this:

workspace_folder/        -- WORKSPACE
  src/                   -- SOURCE SPACE
    CMakeLists.txt       -- 'Toplevel' CMake file, provided by catkin
    package_1/
      CMakeLists.txt     -- CMakeLists.txt file for package_1
      package.xml        -- Package manifest for package_1
    ...
    package_n/
      CMakeLists.txt     -- CMakeLists.txt file for package_n
      package.xml        -- Package manifest for package_n

Services are another way nodes can communicate with each other. Services allow nodes to send a request and receive a response.

You can look up the type of a service. Then using rossrv you can get more information on the that service. For example:

rosservice type /spawn | rossrv show

There is also such a thing as the ROS parameter server. It stores data.

You can look at all this data by using the rosparam command. You can list the parameters, set them and even save and load them.

Service files (srv) are just like msg files, except they contain two parts: a request and a response. The two parts are separated by a '—' line. Here is an example of a srv file:

int64 A
int64 B
---
int64 Sum

Adding a ROS Service

Here are the steps to add a ROS service to a package. These are similar to adding a message.

  • Add a .srv file to the srv/ directory of a package
  • Make sure message_generation and message_runtime build and runtime dependencies are enabled in the package.xml file.
  • Add message_generation to the find_package() function
  • Make sure the service is added to the add_service_files() function

When this is done, running catkin_make install will build all the necessary stuff and also generate the header files required.

Building a ROS Service/Client

A service/client is another form of communication in ROS. Instead of relying on publisher/subscriber messages, which are asynchronous, you have a synchronous service based communication. A client calls a service and waits for a response.

  1. First define the service you will use in the package. See Adding a ROS service.
  2. Write a server node in the srv/ folder
    1. Server node includes the generated header for the service
    2. Server node has a function that returns a boolean and takes in the request and the response of the service.
    3. Server node has a main function that:
      1. calls ros::init
      2. has aros::NodeHandle
      3. advertises the service using ros::ServiceServer
      4. ros::spin();
  3. Write a client node in the src/ folder
    1. Has a main
    2. ros::init()
    3. ros::NodeHandle
    4. ros::ServiceClient
    5. calls client.call(srv) which acts as calling the service and gets returned with a response. Pretty neat.
  4. Add the executables in the CMakeLists.txt files
## Declare a cpp executable
add_executable(executable_one src/source_one.cpp src/source_two.cpp src/source_n.cpp) 

To create multiple executables, you just add multiple instances of that line:

## Declare a cpp executable 
add_executable(executable_one src/source_one.cpp src/source_two.cpp src/source_n.cpp) 
add_executable(executable_two src/source_one.cpp src/source_two.cpp src/source_n.cpp) 
add_executable(executable_three src/source_one.cpp src/source_two.cpp src/source_n.cpp)

tf keeps track of all these frames over time, and allows you to ask questions like:

  • Where was the head frame relative to the world frame, 5 seconds ago?
  • What is the pose of the object in my gripper relative to my base?
  • What is the current pose of the base frame in the map frame?
  • A ROS transform contains a pose (x,y,z) and a quaternion rotation (w, r, p, y)

Transform is a deprecated package with tf2 being the new one.

I did the tutorials where I created a broadcaster and a listener in c++. I also did some stuff where you can compute the transform between two frames and convert it to a velocity command to a robot.

There are two things that you need to do to use tf. You have to listen and broadcast them.

  • Listen - Receive and buffer all coordinate frames that are broadcaster in the system, and query for specific transforms between frames
  • Broadcast - Send out the relative prose of coordinate frames to the rest of the system

There is a REP that outlines lots of good best practice stuff when defining your robot link.

Quaternions

For learning about quaternions check out the OGRE Quaternions intro.

For conversions use this calculator link.

Transform Debugging

You can use rosrun tf2_tools view_frames.py to show you information about the frames.

You can use rosrun tf tf_monitor frame1 frame2 to show you timing info.

tf::MessageFilter

tf::MessageFilter is a function that allows us to process stamped datatypes.

turtle1 wants to know its position relative to itself

  • listen to the topic where turtle3's pose is being published
  • wait until transforms into the desired frame are ready
  • do its operations

tf::TransformListener

Convenient class that allows to do the following:

  • Create a listener for frames
  • Handle transforms such as points from one frame to another

robot_state_publisher

The robot state publisher helps you to broadcast the state of your robot to the tf transform library.

It needs two things to run:

  • The URDF file
  • A source that publishes the joint positions as a sensor_msgs/JointState

It subscribes to joint_states topic for joint position information.

It uses the following parameters

  • robot_description(URDF map)
  • tf_prefix(string)
  • publish_frequency(double)

The rostopic command lets you monitor all aspects of a ROS topic.

You can also use rostopic to publish data of any message into a ROS topic.

  • rostopic hz <topic> : look at how often a message is being sent
  • rostopic pub <topic> <data> : publish data to the topic

When using rostopic pub, make sure you do not have a / before the message name or else autocomplete won't work!!!

Recording and playing back data is really nice and easy with ROS.

To record everything you run:

    rosbag record -a

To play back a bag file you run:

    rosbag play <your bag file>

URDF is an XML file that stands for Unified Robot Description Format.

Unfortunately the tutorials do not give you a step by step guide on how to make a URDF. Instead they just explain a sample URDF tutorial project, which leaves me guessing as to how integrate a URDF in an existing package.

There is a Solidworks to URDF exporter but is old and does not work very well. Do not use it! You are much better off learning how to code your own URDF files.

In a URDF there is a tree structure with one root link. The way you organize these links is with joints. You declare the links and then specify joints between them. If you have two links with no joint specified, RViz will give you an error.

If there are any joints in a mesh, you need to run the joint_state_publisher and also the robot_state_publisher. That means in your launch file you will have the following:

<node name="joint_state_publisher" pkg="joint_state_publisher" type="joint_state_publisher" />
<node name="robot_state_publisher" pkg="robot_state_publisher" type="state_publisher" />

You specify meshes in a URDF with the following:

<mesh filename="package://NAME_OF_PACKAGE/path"/>

You can use the command check_urdf to text the URDF file. URDF_basic

For URDF files to work in gazebo they need to have the following:

  • A header robot tag with an optional xml namespace. Essentially, the following:
<robot name="rrbot" xmlns:xacro="http://www.ros.org/wiki/xacro"> 
  • <intertia> element within each <link> element.

Positioning

The link tab has an origin tag with rpy and xyz params. These only change the origin of the object. They do not change the position. To change the position you set up a joint.

:URDF_basic: http://wiki.ros.org/urdf/Tutorials/Create%20your%20own%20urdf%20file :Gazebo_tut: http://gazebosim.org/tutorials/?tut=ros_urdf#Simplifycollisionmodel

Xacro

Xacro is a URDF macro scripting language that gives you functionality to create more powerful and dynamically generated URDF code. It is a bit tricky to learn but it is very helpful.

The way it works is that you make a xacro file and then have the URDF get automatically generated.

You need these two lines at the top of a xacro file.

<?xml version="1.0"?>
<robot xmlns:xacro="http://www.ros.org/wiki/xacro" name="firefighter">

Here is a link to the best tutorial

  • ros.txt
  • Last modified: 2019/03/31 14:49
  • (external edit)