机器人操作系统ROS(23):urdf模型

INDEX
1. pre-required urdf_tutorial package
1.1 About joint_state_publisher package
1.2 About pr2_description package
3. Building a Visual Robot Model from Scratch
3.1 only one simple shape by link
3.2 Multiple Shapes links by fixed-joint
3.3 Set Origins by origin
3.4 urdf with Material Girl
3.5 Finishing
5. Building a Movable Robot Model
5.1 Head
5.2 Gripper
5.3 Gripper Arm
5.4 Other Types of Joints
5.5 Specifying the Pose
7. Adding Physical and Collision Properties
7.1 Collision
7.2 Physical Properties
9. xacro Package
9.1 Property and Property Blocks
9.2 Math expressions
9.3 Conditional Blocks
9.4 Rospack commands
9.5 Macros
9.7 Including other xacro files
9.8 YAML support
11. Using Xacro to Clean Up a URDF File
11.1 Using Xacro
11.2 Constants
11.3 Math
11.4 Macros
11.5 Practical Usage
13. Understanding the PR2 Robot Description
15. Create your own urdf file
15.1 Create the tree structure
15.2 Add the dimensions
15.3 Completing the Kinematics
17. Parse a urdf file
19. Using the robot state publisher on your own robot
21. Using urdf with robot_state_publisher
21.1 Create the URDF File
21.2 Publishing the State
21.3 Launch File
21.4 Viewing the Results
23. Using a URDF in Gazebo
23.1 Background
23.2 Converting to Gazebo
23.3 The Element
23.4 Prerequisites
23.5 Header of a URDF File
23.6 Fixing A Model to the World
23.7 example link from RRBot
23.8 STL and Collada files
23.9 Verifying the Gazebo Model Works
25 Using Gazebo plugins with ROS
27 ROS Control
29 err
APP:
A1. TOOLS
A. urdf-XML-sensor

( URDF需要先了解:wiki.ros.org/urdf/Tutorials. )

1. pre-required of urdf_tutorial package

we’re going to build a visual model of a robot that vaguely looks like R2D2 and make it move in Gazebo. Before continuing, make sure you have the joint_state_publisher and pr2_description packages by installing urdf_tutorial.
$ sudo apt-get install ros-indigo-urdf-tutorial

1.1 About joint_state_publisher package

This package publishes sensor_msgs/JointState messages for a robot.
The package reads the robot_description parameter, finds all of the non-fixed joints and publishes a JointState message with all those joints defined.
Can be used in conjunction with the robot_state_publisher node to also publish transforms for all joint states.

—— sensor_msgs/JointState Message Definition
# This is a message that holds data to describe the state of a set of torque controlled joints.
# The state of each joint (revolute or prismatic) is defined by:
# * the position of the joint (rad or m),
# * the velocity of the joint (rad/s or m/s) and
# * the effort that is applied in the joint (Nm or N).
# Each joint is uniquely identified by its name
# The header specifies the time at which the joint states were recorded.
std_msgs/Header header
string[] name
float64[] position
float64[] velocity
float64[] effort

——> input
About data input, There are possible four sources for the value of each JointState:
* Values directly input through the GUI
* JointState messages that the node subscribes to
* The value of another joint
* The default value

output ——>
Published Topics: joint_states
Parameters: robot_description (String, default: None), Contents of the URDF file for the robot

—— parameters
robot_description :
Contents of the URDF file for the robot.
Dependent Joints:
Can specified through the dependent_joints parameter or the mimic tag in the URDF to lets you constrain certain joints to be equal to other joints, or multiples of other joints.
Default value:
The default value is zero. If zero is not a permissible value (max+min)/2 is used. To override the default value for some joints, use the zeros parameter.

—— Example YAML file:
Examples of how to set the dependent_joints and the zeros parameters using YAML syntax.
dependent_joints:
joint_D: {parent: joint_A, factor: 3 }
joint_E: {parent: joint_B }
joint_F: {parent: joint_C, factor: -1 }
zeros:
joint_A: 1.57
joint_B: 0.785

1.2 About pr2_description package

This package contains the description (mechanical, kinematic, visual, etc.) of the PR2 robot. The files in this package are parsed and used by a variety of other components. Most users will not interact directly with this package.

—— pr2_description organized subdirectories:
* urdf/ ,contains (xacro representations of) urdf descriptions of various parts of the PR2 (arm, torso, etc.).
* robots/ ,contains (xacro representations of) urdf descriptions of the full robot, that refer to the macros in urdf
* gazebo/ ,contains (xacro representations of) urdf descriptions of simulated PR2 components, like the simulated battery controller.
* meshes/ , contains mesh files (.stl,.dae) for visualization and collision properties.

To see the PR2 URDF graphically:
$ rosrun xacro xacro.py `rospack find pr2_description`/robots/pr2.urdf.xacro > pr2.urdf
$ rosrun urdf urdf_to_graphiz pr2.urdf
$ evince pr2.pdf

To use the original Kinect with the PR2 (either robot or simulation), set the KINECT1 environment variable to true.
export KINECT1=true
To use a Kinect2 with the PR2 (either robot or simulation), set the KINECT2 environment variable to true.
export KINECT2=true
If both variables are set, the Kinect 2 will take precedence over the original Kinect.

3. Building a Visual Robot Model from Scratch

Learn how to build a visual model of a robot looks like R2D2 that you can view in Rviz

3.1 only one simple shape by link

this is a robot with the name myfirst, that contains only one link (a.k.a. part), whose visual component is just a cylinder .6 meters long with a .2 meter radius.

To examine the model by launch the display.launch file:
$ roslaunch urdf_tutorial display.launch model:=urdf/01-myfirst.urdf
or,
$ roslaunch urdf_tutorial display.launch model:=’$(find urdf_tutorial)/urdf/01-myfirst.urdf’
Note that the roslaunch line above does three things:
* Loads the specified model into the parameter server
* Runs nodes to publish sensor_msgs/JointState and transforms
* Starts Rviz with a configuration file

NOTE:
* The fixed frame is transform frame where the center of the grid is located. Here, it’s a frame defined by our one link, base_link.
* The visual element (the cylinder) has its origin at the center of its geometry as a default. Hence, half the cylinder is below the grid.

3.2 Multiple Shapes links by fixed-joint

Lets look at how to add multiple shapes/links.
If we just add more link elements to the urdf, the parser won’t know where to put them. So, we have to add joints. Joint elements can refer to both flexible and inflexible joints.
We’ll start with inflexible, or named fixed joints.

$ roslaunch urdf_tutorial display.launch model:=urdf/02-multipleshapes.urdf

x+ axis direction is 0.6, y+ is 0.2 width, and z+ is 0.1 deepth.
But Both of the shapes overlap with each other, because they share the same origin. If we want them not to overlap we must define more origins–>

3.3 Set Origins by origin

So R2D2’s leg attaches to the top half of his body, on the side where we specify the origin of the JOINT to be. Also, it doesn’t attach to the middle of the leg, it attaches to the upper part, so we must offset the origin for the leg as well. We also rotate the leg so it is upright.

* The joint’s origin is defined in terms of the parent’s reference frame, ‘joint — origin xyz=”0.22 0 .25’, we are .22 meters in the x direction (left) and .25 meters in the z direction (up). This means that the origin for the child link will be up and to the left, regardless of the child link’s visual origin tag. Since we didn’t specify a rpy (roll pitch yaw) attribute, the child frame will be default have the same orientation as the parent frame.
* The leg’s visual origin, origin rpy=”0 1.57075 0″ xyz=”0 0 -0.3″, has both a xyz and rpy offset. This defines where the center of the visual element should be, relative to its origin. Since we want the leg to attach at the top, we offset the origin down by setting the z offset to be -.3 meters. And since we want the long part of the leg to be parallel to the z axis, we rotate the visual part PI/2 around the Y axis.

$ roslaunch urdf_tutorial display.launch model:=urdf/03-origins.urdf

The launch file runs packages that will create TF frames for each link in your model based on your URDF. Rviz uses this information to figure out where to display each shape.

3.4 urdf with Material Girl

Color? My robot are not red? Let’s take a look at the material tag:

$ roslaunch urdf_tutorial display.launch model:=urdf/04-materials.urdf

3.5 Finishing

Now we finish with a few more shapes. Most notably, we add a sphere and a some meshes. We’ll also add few other pieces that we’ll use later.
$ roslaunch urdf_tutorial display.launch model:=urdf/05-visual.urdf

About codes to add the sphere

Above The meshes were borrowed from the PR2, meaning you’ll need the package pr2_description to be able to see them.
* The meshes can be imported in a number of different formats. STL is fairly common, but the engine also supports DAE, which can have its own color data, meaning you don’t have to specify the color data.
* Meshes can also be sized using relative scaling parameters or a bounding box size.

Ok we have a R2D2-like URDF model now,
next step, make it mve.

5. Building a Movable Robot Model

In the previous model, all of the joints were fixed.
Now we’ll explore three other important types of joints: continuous连续, revolute旋转,prismatic棱形副。
URDF source here:

$ roslaunch urdf_tutorial display.launch model:=urdf/06-flexible.urdf gui:=True
This will visualize and control this model also pop up a GUI that allows you to control the values of all the non-fixed joints.

Now focus on three example joints.

5.1 Head

swivel旋转关节,The connection between the body and the head is a continuous joint, meaning that it can take on any angle from negative infinity to positive infinity. The wheels are also modeled like this, so that they can roll in both directions forever.
The only additional information we have to add is the axis of rotation, here specified by an xyz which specifies a vector around which the head will rotate. Since we want it to go around the z axis, we specify the vector “0 0 1”.

5.2 Gripper

Both the right and the left gripper joints are modeled as revolute joints. revolute joints means that they rotate in the same way that the continuous joints do, but they have strict limits. Hence, we must include the limit tag specifying the upper and lower limits of the joint (in radians). We also must specify a maximum velocity and effort for this joint. You can also specify the maximum effort and velocity for continuous joints but you don’t have to.

5.3 Gripper Arm

The gripper arm is a different kind of joint…namely a prismatic joint. This means that it moves along an axis, not around it. This translational movement is what allows our robot model to forwared-extend and backword-retract its gripper arm.
The limits of the prismatic arm are specified in the same way as a revolute joint, except that the units are meters, not radians.

5.4 Other Types of Joints

There are two other kinds of joints that move around in space. Whereas the prismatic joint can only move along one dimension, a planar joint can move around in a plane, or two dimensions. Furthermore, a floating joint is unconstrained, and can move around in any of the three dimensions.

5.5 Specifying the Pose

As you move the sliders around in the GUI, the model moves in Rviz. How is this done?
First the GUI parses the URDF and finds all the non-fixed joints and their limits. Then, it uses the values of the sliders to publish sensor_msgs/JointState messages.
Those are then used by robot_state_publisher to calculate all of transforms between the different parts. The resulting transform tree is then used to display all of the shapes in Rviz.

7. Adding Physical and Collision Properties

7.1 Collision

So far, we’ve only specified our links with a single sub-element, visual, which defines (not surprisingly) what the robot looks like. However, in order to get collision detection to work or to simulate the robot in something like Gazebo, we need to define a collision element as well.
URDF source:

Code for our new base link:

* The collision element is a direct subelement of the link object, at the same level as the visual tag
* The collision element defines its shape the same way the visual element does, with a geometry tag.
* You can also specify an origin in the same way as a subelement of the collision tag (as with the visual)

In many cases, you’ll want the collision geometry and origin to be exactly the same as the visual geometry and origin. However, there are two main cases where you wouldn’t:
* Quicker Processing – Doing collision detection for two meshes is a lot more computational complex than for two simple geometries. Hence, you may want to replace the meshes with simpler geometries in the collision element.
* Safe Zones – You may want to restrict movement close to sensitive equipment. For instance, if we didn’t want anything to collide with R2D2’s head, we might define the collision geometry to be a cylinder encasing his head to prevent anything from getting to near his head.

7.2 Physical Properties

In order to get your model to simulate properly, you need to define several physical properties of your robot, i.e. the properties that a physics engine like Gazebo would need.

7.2.1 Inertia 惯性
Every link element being simulated needs an inertial tag:

* This element is also a subelement of the link object.
* The mass is defined in kilograms.
* The 3×3 rotational inertia matrix is specified with the inertia element. Since this is symmetrical, it can be represented by only 6 elements, as such.
ixx/ixy/ixz,ixy/iyy/iyz,ixz/iyz/izz
* This information can be provided to you by modeling programs such as MeshLab.
* The inertia tensor depends on both the mass and the distribution of mass of the object. A good first approximation is to assume equal distribution of mass in the volume of the object and compute the inertia tensor based on the object’s shape, as outlined above.
* If unsure what to put, a matrix with ixx/iyy/izz=1e-3 or smaller is often a reasonable default for a mid-sized link (it corresponds to a box of 0.1 m side length with a mass of 0.6 kg). Although often chosen, the identity matrix is a particularly bad default, since it is often much too high (it corresponds to a box of 0.1 m side length with a mass of 600 kg!).
* You can also specify an origin tag to specify the center of gravity and the inertial reference frame (relative to the link’s reference frame).
* When using realtime controllers, inertia elements of zero (or almost zero) can cause the robot model to collapse without warning, and all links will appear with their origins coinciding with the world origin.

7.2.2 Contact Coefficients
You can also define how the links behave when they are in contact with one another. This is done with a subelement of the collision tag called contact_coefficients. There are three attributes to specify:
mu – The friction coefficient
kp – Stiffness coefficient
kd – Dampening coefficient

7.2.3 Joint Dynamics
How the joint moves is defined by the dynamics tag for the joint. There are two attributes here:
friction – The physical static friction. For prismatic joints, the units are Newtons. For revolving joints, the units are Newton meters.
damping – The physical damping value. For prismatic joints, the units are Newton seconds per meter. For revolving joints, Newton meter secons per radian.

7.2.4 Other Tags
In the realm of pure URDF (i.e. excluding Gazebo-specific tags), there are two remaining tags to help define the joints: calibration and safety controller.

9. xacro Package

xacro is a macro language. xacro package is most useful when working with large XML documents such as robot descriptions.
Consider the following Xacro XML example:

Above code expands to: If we also define macros for pr2_upperarm and pr2_forearm, then this snippet could expand to describe an entire robotic arm.

9.1 Property and Property Blocks

Properties are named values that can be inserted anywhere into the XML document. Property blocks are named snippets of XML that can be inserted anywhere that XML is allowed. Both use the property tag to define values. Property tags cannot be declared inside of a xacro:macro. The following example shows how to declare and use a property:

The two properties are inserted into the geometry expression by placing the names inside dollared-braces (${}). If you want a literal “${“, you should escape it as “$${“.

Here’s an example of using a property block:

9.2 Math expressions

Within dollared-braces (${}), you can also write simple math expressions. Currently, basic arithmetic and variable substitution is supported. Here’s an example:

9.3 Conditional Blocks

9.4 Rospack commands

Xacro allows you to use certain rospack commands with dollared-parentheses ($()).

Since ROS Indigo, it is also possible to define defaults like so:

Using this you can run xacro like:

9.5 Macros

The main feature of xacro is its support for macros. Define macros with the macro tag, and specify the macro name and the list of parameters. The list of parameters should be whitespace separated. They become macro-local properties.

9.7 Including other xacro files

You can include other xacro files using the xacro:include tag:

To avoid name clashes between properties and macros of various included files, you can specify a namespace for the included file – providing the attribute ns:

9.8 YAML support

11. Using Xacro to Clean Up a URDF File

you might be sick of doing all sorts of math to get very simple robot descriptions to parse correctly. you can use the xacro package to make your life simpler. It’s easy to do three things that are very helpful.
* Constants
* Simple Math
* Macros
Here take a look at all these shortcuts to help reduce the overall size of the URDF file and make it easier to read and maintain. It is heavily used in packages such as the urdf.

11.1 Using Xacro

The xacro program runs all of the macros and outputs the result. Typical usage looks something like this:
$ rosrun xacro xacro model.xacro > model.urdf
You can also automatically generate the urdf in a launch file. This is convenient because it stays up to date and doesn’t use up hard drive space. However, it does take time to generate, so be aware that your launch file might take longer to start up.

You must specify a namespace in order for the file to parse properly. For example, these are the first two lines of a valid xacro file:

11.2 Constants

Let’s take a quick look at our base_link in R2D2.

The information here is a little redundant. We specify the length and radius of the cylinder twice. Worse, if we want to change that, we need to do so in two different places.
Fortunately, xacro allows you to specify properties which act as constants. Instead, of the above code, we can write this.

* The two values are specified in the first two lines. They can be defined just about anywhere (assuming valid XML), at any level, before or after they are used. Usually they go at the top.
* Instead of specifying the actual radius in the geometry element, we use a dollar sign and curly brackets to signify the value.
* This code will generate the same code shown above.

The value of the contents of the ${} construct are then used to replace the ${}. This means you can combine it with other text in the attribute.

This will generate

However, the contents in the ${} don’t have to only be a property, which brings us to next point…

11.3 Math

You can build up arbitrarily complex expressions in the ${} construct using the four basic operations (+,-,*,/), the unary minus, and parenthesis. Exponentiation and modulus are not supported. Examples:

11.4 Macros

Here’s the biggest and most useful component to the xacro package.

11.4.1 Simple Macro

Let’s take a look at a simple useless macro.

This code will generate the following.

* The name is not technically a required element, but you need to specify it to be able to use it.
* Every instance of the <xacro:$name> is replaced with the contents of the xacro:macro tag.
* !!! If the xacro with a specified name is not found, it will not be expanded and will NOT generate an error. </xacro:$name>

11.4.2 Parameterized Macro

You can also parameterize macros so that they don’t generate the same exact text every time. When combined with the math functionality, this is even more powerful. First, let’s take an example of a simple macro used in R2D2.

This can be used with the code

The parameters act just like properties, and you can use them in expressions

11.5 Practical Usage

The xacro language is rather flexible in what it allows you to do. Here are a few useful ways that the xacro is used in the R2D2 model, in addition to the default inertial macro shown above:

To see the model generated by a xacro file, run this command:
$ roslaunch urdf_tutorial xacrodisplay.launch model:=urdf/08-macroed.urdf.xacro

11.5.1 Leg macro
Often you want to create multiple similar looking objects in different locations. Often, there will be some symmetry to the locations. You can use a macro and some simple math to reduce the amount of code you have to write, like we do with R2’s two legs.

* Use a name prefix to get two similarly named objects
* Use math to calculate joint origins.
* Using a reflect parameter, and setting it to 1 or -1.

13. Understanding the PR2 Robot Description

Now refers to the description in pr2_defs, which has now been replaced by the one in pr2_description.
In particular, the XML schemas specified in the element are no longer required by Gazebo, and all references to Gazebo plugins are incorrect as their API has changed considerably. Now let’s break down the entire XML piece by piece

The root element for the XML must be robot with a name attribute. XML namespaces are declared here.


Include files containing xacro macros for inidividual robot components. This is like including a header file in C: it sets up a bunch of definitions but doesn’t actually call any of them.


Some useful comments

we actually use the macros defined above. Here, we define PR2’s base, using the xacro:pr2_base_v0 macro, with name parameter equal to “base” and an origin parameter block. After running the original file through the xacro preprocessor, this element will be replaced with a rather long URDF definition of the base and its components.

Similarly, we define the PR2 torso, using the xacro:pr2_torso_v0 macro, which can be found in the included file pr2_description/urdf/torso_v0/torso.urdf.xacro.

PR2 head sensor packages, including two interlacing stereo cameras and a high resolution Prosilica GC2450 camera.

PR2 tilting Hokuyo laser range scanner.

15. Create your own urdf file

15.1 Create the tree structure

Now start creating your own urdf robot description file. we’ll create the URDF description of the “robot” shown in the image below.

The robot in the image is a tree structure. Let’s start very simple, and create a description of that tree structure, without worrying about the dimensions etc.
Create a file called my_robot.urdf:

So, just creating the structure is very simple! Now let’s see if we can get this urdf file parsed. There is a simple command line tool that will parse a urdf file for you, and tell you if the syntax is correct.
First, You might need to install, urdfdom as an upstream, ROS independent package:
$ sudo apt-get install liburdfdom-tools
Then run the check command
$ rosrun urdf check_urdf my_robot.urdf # older versions
$ rosrun urdf_parser check_urdf my_robot.urdf # electric and fuerte
$ rosrun urdfdom check_urdf my_robot.urdf # groovy
$ check_urdf my_robot.urdf # hydro onward
———
robot name is: test_robot
———- Successfully Parsed XML —————
root Link: link1 has 2 child(ren)
child(1): link2
child(2): link3
child(1): link4

15.2 Add the dimensions

So now that we have the basic tree structure, let’s add the appropriate dimensions. As you notice in the robot image, the reference frame of each link (in green) is located at the bottom of the link, and is identical to the reference frame of the joint. So, to add dimensions to our tree, all we have to specify is the offset from a link to the joint(s) of its children. To accomplish this, we will add the field to each of the joints.

Let’s look at the second joint Joint2.
Joint2 is offset in the Y-direction from link1,
a little offset in the negative X-direction from link1,
and it is rotated 90 degrees around the Z-axis. So, we need to add the following element:

If you repeat this for all the elements our URDF will look like this:

Update your file my_robot.urdf and run it through the parser:
$ check_urdf my_robot.urdf

15.3 Completing the Kinematics

What we didn’t specify yet is around which axis the joints rotate. Once we add that, we actually have a full kinematic model of this robot! All we need to do is add the element to each joint. The axis specifies the rotational axis in the local frame.

So, if you look at joint2, you see it rotates around the positive Y-axis. So, simple add the following xml to the joint element:

Similarly, joint1 is rotating around the following axis:

Note that it is a good idea to normalize the axis.

If we add this to all the joints of the robot, our URDF looks like this:

Update your file my_robot.urdf and run it through the parser:
$ check_urdf my_robot.urdf

That’s it, you created your first URDF robot description! Now you can try to visualize the URDF using graphiz:
$ urdf_to_graphiz my_robot.urdf
$ evince test_robot.pdf

17. Parse a urdf file

with the same my_robot.urdf file description of the robot shown above.
first create a package with a dependency on the urdf parser in our sandbox:
$ cd ~/catkin_ws/src
$ catkin_create_pkg testbot_description urdf
$ cd testbot_description

Now create a /urdf folder to store the urdf file we just created:
$ mkdir urdf
$ cd urdf
This follows the convention of always storing your robot’s URDF file in a ROS package named MYROBOT_description and within a subfolder named /urdf.
Other standard subfolders of your robot’s description package include /meshes, /media and /cad, like so:
/MYROBOT_description
package.xml
CMakeLists.txt
/urdf
/meshes
/materials
/cad

Next, copy your my_robot.urdf file to the package and folder we just created:
$ cp /path/to/…/testbot_description/urdf/my_robot.urdf .

Create a folder src/ and create a file called src/parser.cpp:
#include
#include “ros/ros.h”

int main(int argc, char** argv){
ros::init(argc, argv, “my_parser”);
if (argc != 2){
ROS_ERROR(“Need a urdf file as argument”);
return -1;
}
std::string urdf_file = argv[1];

urdf::Model model;
if (!model.initFile(urdf_file)){
ROS_ERROR(“Failed to parse urdf file”);
return -1;
}
ROS_INFO(“Successfully parsed urdf file”);
return 0;
}

urdf::Model is a class containing robot model data structure.
Every Robot Description File (URDF) can be described as a list of Links (urdf::Model::links_) and Joints (urdf::Model::joints_).
The connection between links(nodes) and joints(edges) should define a tree (i.e. 1 parent link, 0+ children links).

try to run this code.
First add the following lines to your CMakeList.txt file:
add_executable(parser src/parser.cpp)
target_link_libraries(parser ${catkin_LIBRARIES})
build your package,
$ cd ~/catkin_ws
$ catkin_make
and run it.
$ ./parser my_robot.urdf
— [ INFO] 1254520129.560927000: Successfully parsed urdf file

A good example of the URDF model class in action is rviz’s Robot::load

19. Using the robot state publisher on your own robot

you can publish the state of your robot to tf, using the robot state publisher.
Example launch file

21. Using urdf with robot_state_publisher

A full example of a robot model with URDF that uses robot_state_publisher.
First, we create the URDF model with all the necessary parts. Then we write a node which publishes the JointState and transforms. Finally, we run all the parts together.

21.1 Create the URDF File

Here is the URDF file for a 7-link model roughly approximating R2-D2.

21.2 Publishing the State

Now we need a method for specifying what state the robot is in. To do this, we must specify all three joints and the overall odometry. Start by creating a package:
$ cd %TOP_DIR_YOUR_CATKIN_WS%/src
$ catkin_create_pkg r2d2 roscpp rospy tf sensor_msgs std_msgs

then create src/state_publisher.cpp file:
#include
#include
#include
#include

int main(int argc, char** argv) {
ros::init(argc, argv, “state_publisher”);
ros::NodeHandle n;
ros::Publisher joint_pub = n.advertise(“joint_states”, 1);
tf::TransformBroadcaster broadcaster;
ros::Rate loop_rate(30);

const double degree = M_PI/180;

// robot state
double tilt = 0, tinc = degree, swivel=0, angle=0, height=0, hinc=0.005;

// message declarations
geometry_msgs::TransformStamped odom_trans;
sensor_msgs::JointState joint_state;
odom_trans.header.frame_id = “odom”;
odom_trans.child_frame_id = “axis”;

while (ros::ok()) {
//update joint_state
joint_state.header.stamp = ros::Time::now();
joint_state.name.resize(3);
joint_state.position.resize(3);
joint_state.name[0] =”swivel”;
joint_state.position[0] = swivel;
joint_state.name[1] =”tilt”;
joint_state.position[1] = tilt;
joint_state.name[2] =”periscope”;
joint_state.position[2] = height;

// update transform
// (moving in a circle with radius=2)
odom_trans.header.stamp = ros::Time::now();
odom_trans.transform.translation.x = cos(angle)*2;
odom_trans.transform.translation.y = sin(angle)*2;
odom_trans.transform.translation.z = .7;
odom_trans.transform.rotation = tf::createQuaternionMsgFromYaw(angle+M_PI/2);

//send the joint state and transform
joint_pub.publish(joint_state);
broadcaster.sendTransform(odom_trans);

// Create new robot state
tilt += tinc;
if (tilt<-.5 || tilt>0) tinc *= -1;
height += hinc;
if (height>.2 || height<0) hinc *= -1; swivel += degree; angle += degree/4; // This will adjust as needed per iteration loop_rate.sleep(); } return 0; } 21.3 Launch File This launch file assumes you are using the package name “r2d2” and node name “state_publisher” and you have saved urdf to the “r2d2” package.

21.4 Viewing the Results

Make sure to add the tf dependency in addition to the other dependencies:
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs tf)

Notice that roscpp is used to parse the code that we wrote and generate the state_publisher node. We also have to add the following to the end of the CMakelists.txt in order to generate the state_publisher node:
include_directories(include ${catkin_INCLUDE_DIRS})
add_executable(state_publisher src/state_publisher.cpp)
target_link_libraries(state_publisher ${catkin_LIBRARIES})

build it using:
$ catkin_make
launch the package (assuming that our launch file is named display.launch):
$ roslaunch r2d2 display.launch

Run rviz in a new terminal using:
$ rosrun rviz rviz
Choose odom as your fixed frame (under Global Options). Then choose “Add Display” and add a Robot Model Display and a TF Display

23. Using a URDF in Gazebo

The Universal Robotic Description Format (URDF) is an XML file format used in ROS to describe all elements of a robot. To use a URDF file in Gazebo, some additional simulation-specific tags must be added to work properly with Gazebo.
This tutorial explains the necessary steps to successfully use your URDF-based robot in Gazebo, saving you from having to create a separate SDF file from scratch and duplicating description formats. Under the hood, Gazebo will then convert the URDF to SDF automatically.

23.1 Background

While URDFs are a useful and standardized format in ROS, they are lacking many features and have not been updated to deal with the evolving needs of robotics. URDF can only specify the kinematic and dynamic properties of a single robot in isolation. URDF can not specify the pose of the robot itself within a world. It is also not a universal description format since it cannot specify joint loops (parallel linkages), and it lacks friction and other properties. Additionally, it cannot specify things that are not robots, such as lights, heightmaps, etc.
On the implementation side, the URDF syntax breaks proper formatting with heavy use of XML attributes, which in turn makes URDF more inflexible. There is also no mechanism for backward compatibility.
To deal with this issue, a new format called the Simulation Description Format (SDF) was created for use in Gazebo to solve the shortcomings of URDF. SDF is a complete description for everything from the world level down to the robot level. It is scalable, and makes it easy to add and modify elements. The SDF format is itself described using XML, which facilitates a simple upgrade tool to migrate old versions to new versions. It is also self-descriptive.

23.2 Converting to Gazebo

There are several steps to get a URDF robot properly working in Gazebo. The following is an overview of steps:
Required
* An element within each element must be properly specified and configured.
Optional
Add a element for every Convert visual colors to Gazebo format
Convert stl files to dae files for better textures
Add sensor plugins
Add a element for every
Set proper damping dynamics
Add actuator control plugins
Add a element for the element
Add a link if the robot should be rigidly attached to the world/base_link

23.3 The Element

The element is an extension to the URDF used for specifying additional properties needed for simulation purposes in Gazebo. It allows you to specify the properties found in the SDF format that are not included in the URDF format.
There are three different types of elements – one for the tag, one for tags, and one for tags.

element for the tag
If a element is used without a reference=”” property, it is assumed the element is for the whole robot model.

23.4 Prerequisites

The first step to getting your robot working in Gazebo is to have a working URDF file
Test your URDF by viewing it in Rviz before proceeding to configure your robot with Gazebo.
a) Getting RRBot
RRBot, or ”Revolute-Revolute Manipulator Robot”, is a simple 3-linkage, 2-joint arm that we will use to demonstrate various features of Gazebo and URDFs.
$ cd ~/catkin_ws/src/
$ git clone https://github.com/ros-simulation/gazebo_ros_demos.git
$ cd ..
$ catkin_make

b) View in Rviz
To check if everything is working, launch RRBot in Rviz:
$ roslaunch rrbot_description rrbot_rviz.launch
loo like :

The gazebo_ros_control tutorial will explain how to use Rviz to monitor the state of your simulated robot by publishing /joint_states directly from Gazebo. In the previous example, the RRBot in Rviz is getting its /joint_states from a fake joint_states_publisher node
REF: http://gazebosim.org/tutorials?tut=ros_control

c) Examine the RRBot URDF
view the rrbot.xacro file now:
$ rosed rrbot_description rrbot.xacro

Note that we are using Xacro to make some of the link and joint calculations easier. We are also including two additional files:
* rrbot.gazebo a Gazebo specific file that includes most of our Gazebo-specific XML elements including the tags
* materials.xacro a simple Rviz colors file for storing rgba values, not really necessary but a nice convention

d) View in Gazebo
launch RRBot into Gazebo:
$ roslaunch rrbot_gazebo rrbot_world.launch

In the launched Gazebo window you should see the robot standing straight up. Despite there being no intentional disturbances in the physics simulator by default, numerical errors should start to build up and cause the double inverted pendulum to fall after a few seconds. The following is a mid-swing screenshot of the RRBot:
https://bitbucket.org/osrf/gazebo_tutorials/raw/default/ros_urdf/figs/Swinging_Arm.png

23.5 Header of a URDF File

23.6 Fixing A Model to the World

If you would like your URDF model to be permanently attached to the world frame (the ground plane), you must create a “world” link and a joint that fixes it to the base of your model. RRBot accomplishes this with the following:

If however you have a mobile base or some other moving robot, you do not need this link or joint.

23.7 example link from RRBot

a) Units
As per ROS REP 103: Standard Units of measure and Coordinate Conventions, units in Gazebo should be specified in meters and kilograms. Gazebo could possibly be used with imperial units if the constants such as gravity were changed manually, but by default gravity is 9.81 m/s^2. When specifying mass, use units of kilograms.

23.8 STL and Collada files

Like in Rviz, Gazebo can use both STL and Collada files. It is generally recommended you use Collada (.dae) files because they support colors and textures, whereas with STL files you can only have a solidly colored link.

23.9 Verifying the Gazebo Model Works

With Gazebo installed, an easy tool exists to check if your URDF can be properly converted into a SDF. Simply run the following command:
# gazebo2 and below
gzsdf print MODEL.urdf
# gazebo3 and above
gz sdf -p MODEL.urdf
This will show you the SDF that has been generated from your input URDF as well as any warnings about missing information required to generate the SDF.

Note: in Gazebo version 1.9 and greater, some of the debug info has been moved to a log file you can view with:
$ cat ~/.gazebo/gzsdf.log

8.10 Viewing the URDF In Gazebo
Viewing the RRBot in Gazebo was already covered at the beginning of this tutorial.
For your own custom robot, we assume its URDF lives in a ROS package named MYROBOT_description in the subfolder /urdf.
To view your robot and test it in Gazebo, you should be able to now run something like:
$ roslaunch MYROBOT_gazebo MYROBOT.launch
This should launch both the Gazebo server and GUI client with your robot automatically launched spawned inside.

25 Using Gazebo plugins with ROS

adding plugins to your URDF so that different aspects of your robot and the simulated environment can be controlled.

27 ROS Control

analyze the ros_control packages integrated with Gazebo for tight controller/actuator/simulator integration Actuators, controllers, and ros_control.

29 err

ROS message and service calls that are available for use with Gazebo
REF: http://gazebosim.org/tutorials/?tut=ros_urdf

APP:
1. TOOLS

1.1 Verification tools
For example, run this tool on the pr2 urdf, first create the urdf file by running:
$ rosrun xacro xacro.py `rospack find pr2_description`/robots/pr2.urdf.xacro -o /tmp/pr2.urdf

Then run the check by running:
$ check_urdf /tmp/pr2.urdf

Visualization tools
To get a graphviz diagram of your urdf file
$ urdf_to_graphiz pr2.urdf
$ evince pr2.pdf

2. urdf-XML-sensor

An example of a camera sensor element:

An example of a laser scan (ray) sensor element:

机器人操作系统ROS(21):launch文件

0 – Summary

Roslaunch is a tool for easily launching multiple ROS nodes locally or remotely via SSH, as well as setting parameters on the Parameter Server.
It includes options to automatically respawn processes that have already died.
Roslaunch takes in one or more XML configuration files with the .launch extension that specify the parameters to set and nodes to launch, as well as the machines that they should be run on.

1 – Roslaunch Architecture

roslaunch was designed to fit the ROS architecture of complexity via composition: write a simple system first, then combine it with other simple systems to make more complex systems.

In roslaunch, this is expressed through several mechanisms:
1. include : you can easily include other .launch files and also assign them a namespace so that their names do not confict with yours.
2. group : you can group together a collection of nodes to give them the same name remappings. All resource names can be remapped. You can also provide assignment for private node parameters. Remapping arguments can be passed to any node and use the syntax name:=new_name. For example, to configure the talker node to publish to /wg/chatter instead of chatter:
$ rosrun rospy_tutorials talker chatter:=/wg/chatter. You can assign private parameters for a node directly from the command-line using a single underscore _ as a prefix. For example, $rosrun rospy_tutorials talker _param:=1.0, this will sets ~param to 1.0. ROS uses YAML syntax to determine the parameter typing. Note there are some Special keys(double _): __name, __ip and __hostname, __master, __ns.
3. aliased : you can separate machine definitions and node definitions into separate .launch files and use aliases to define which machines get used at runtime. This allows you to reuse the same node definitions for multiple robots. For example, instead of saying that a laser_assembler runs on ‘foo.willowgarage.com’, you can say that it runs on the ’tilt-laser’ machine. The machine definitions then take care of which host is the ’tilt-laser’ machine.

You can use the tag to specify environment variables that need to be set for a particular machine or node. The $(find pkg) syntax let you specify file paths relative to a ROS package, instead of specifying their location on a particular machine. You can also use the $(env ENVIRONMENT_VARIABLE) syntax within include tags to load in .launch files based on environment variables (e.g. MACHINE_NAME).

Roslaunch launches local processes using popen and kills them using POSIX signals. NOTE roslaunch does not guarantee any particular order to the startup of nodes — although this is a frequently requested feature, it is not one that has any particular meaning in the ROS architecture as there is no way to tell when a node is initialized.

2 – Commandline Tools

roslaunch is an important tool that manages the start and stop of ROS nodes. It takes one or more .launch files as arguments.
Most roslaunch command require the name of a launch file. You can either specify the file path of the launch file, or you can specify a package name and launch file in that package:
$ roslaunch [args]
Launch located in , e.g.:
$ roslaunch rospy_tutorials talker_listener.launch
or,
$ roscd package_name
$ roslaunch example.launch
or,Launch the file(s) specified by relative or absolute paths
$ roslaunch pr2_robot/pr2_bringup/pr2.launch

And [args] New in Indigo:
-p port, If you launched roscore on a different port using the -p option.
–wait, Delay the launch until a roscore is detected.
–local, Launch of the local nodes only. Nodes on remote machines will not be run.
–screen, Force all node output to screen. Useful for node debugging.
–dump-params, Print parameters in launch file in YAML format.

If the file you are launching specifies args that require setting, you can do so using an identical syntax to ROS remapping arguments, e.g.:
$ roslaunch my_file.launch arg:=value

2 – roslaunch XML

ROS 的 launch 文档中经常被使用到的三个与参数设置有关的标签 <arg>、<param>、rosparam。arg和param的区别是,param是在node或py等执行文件里面定义的,而arg则是在launch或xml等配置文件里定义的 。

变量标签 arg

<arg>标签给launch文件内部设置参数,通过<arg>标签设置的参数仅在launch文件内有效。

<arg>标签有三种设置参数的方式:

1、直接用此标签设置

2、用此标签声明,用roslaunch命令确定其值

3、用此标签声明,在include 这个launch文件的 父launch文件中确定其值

0、如何声明一个 argument :
<arg name=”arg-name” …/>

1、 如何在声明 argument 时赋值
<arg name=”arg-name” default=”arg-value” />
<arg name=”arg-name” value=”arg-value” />
default 和 value 的区别在于,在命令行中赋值的参数可以覆盖 default,但是不能重写 value 的值。

获取变量值的方式是:
$(arg arg-name)
我们可以通过 $arg$ 来使用该变量,roslaunch 会用给定的参数 $arg-name$ 的值替换整个表达式的值。

2、如何在命令行赋值指定 argument 的值
$ roslaunch package-name launch-file-name arg-name:=arg-value

3、将 argument 值传递给 included launch 文档
<include file=”path-to-file”>
<arg name=”arg-name”  value=”arg-value” />
</include>

注意:若 launch 文档及其 include 的 launch 文档出现相同的 argument,通过如下方式传递给 include launch 文档 :
<arg name=”arg-name” value=”$(arg arg-name)” />
第一个”arg-name”表示 include的launch 文档中的变量;第二个”arg-name”则表示当前 launch 文档中的变量 “arg-name” 指定的变量在当前 launch 文档以及 included launch 文档中都有相同的值。

参数标签 rosparam

尽管 argument(变量)和 parameter(参数)优势可互换,但二者在 ROS 中的意义完全不同:parameters 是 ROS 系统使用的数值,存在 parameter server 上,nodes 可通过ros::param::get函数编程得到,用户可通过rosparam命令获取;与之不同,arguments 仅在 launch 文档内部有意义,nodes 不能直接获取它们的值

前面介绍的<arg>用于设置变量;接下来介绍的两个<param>和<rosparam>标签用于设置参数。

参数访问有三种方式
1、命令行:
rosparam set、rosparam get

2、launch 文档:
<param>、<rosparam>

3、API方式
roscpp: ros::param::set、ros::param::get
rospy: set_param、set_param

<rosparam>  通过配置文档*.yaml文档加载参数
<rosparam file=”$(find navigation_launch)/config/costmap_common_params.yaml” command=”load” ns=”global_costmap” />

<rosparam> 其他常见方式
<rosparam command=”delete” param=”my/param” />
<rosparam param=”a_list”>[1, 2, 3, 4]</rosparam>
<rosparam>
a: 1
b: 2
</rosparam>

参数标签 param

<param>更像是 define 宏,必须在本地 launch 文档中赋值,无法用于在 launch 文档中获取命令中的参数(但可以通过下面介绍 rosrun 方式接收和传递)。定义的参数均会保留在 ROS 参数服务器(PARAMETERS)中,该参数会被节点(NODES)使用进行节点配置。
<launch>
<param name=”param-name-1″ value=”false” />
<node ….>
<param name=”param-name-2″ value=”…”>
</node>
</launch>
注意区别:第一个参数 param-name-1 ,是整个 launch 全局(global)有效;第二个参数 param-name-2 ,只相对(relative)节点局部(private)有效。

rosrun 本身的设计是可以让使用者直接修改节点内的参数,通过以下的方式:
$ rosrun package-name node-name _param-name:=param-value

rosparam可以使用command属性 :

<arg name=”urdf_file” default=”$(find xacro)/xacro.py ‘$(find turtlebot_description)/robots/$(arg base)_$(arg stacks)_$(arg 3d_sensor).urdf.xacro'” />

<param name=”robot_description” command=”$(arg urdf_file)” />

The output of the command will be read and stored as a string. It is strongly recommended that you use the package-relative $(find)/file.txt syntax to specify file arguments. You should also quote file arguments using single quotes due to XML escaping requirements.

env和optenv 标签

These two are using to modify the environment variables that one or more nodes are executed with.

Using env will force the user to have this variable set (roslaunch would fail if the variable is missing) . If you used the optenv expansion arg to set the value of the argument, then, you’d be able to decide the value of the argument simply by setting an environment variable.

The roslaunch evaluates the XML file in a single pass. Includes are processed in depth-first traversal order. Tags are evaluated serially and the last setting wins. Thus, if there are multiple settings of a parameter, the last value specified for the parameter will be used.
Relying on the override behavior can be brittle. There is no guarantee that an override is specified correctly (e.g. if a parameter name is changed in an included file). Instead, it is recommended that override behavior be done using $(arg)/ settings.

substitution args
Roslaunch tag attributes can make use of substitution args, which roslaunch will resolve prior to launching nodes. The currently supported substitution args are:

1. $(env ENVIRONMENT_VARIABLE)
Substitute the value of a variable from the current environment. The launch will fail if environment variable is not set. This value cannot be overridden by tags.

2. $(optenv ENVIRONMENT_VARIABLE)  $(optenv ENVIRONMENT_VARIABLE default_value)
Substitute the value of an environment variable if it is set. If default_value is provided, it will be used if the environment variable is not set. If default_value is not provided, an empty string will be used. default_value can be multiple words separated by spaces.

Examples:3. $(find pkg)
e.g. $(find rospy)/manifest.xml. Specifies a package-relative path. The filesystem path to the package directory will be substituted inline. Use of package-relative paths is highly encouraged as hard-coded paths inhibit the portability of the launch configuration. Forward and backwards slashes will be resolved to the local filesystem convention.

4. $(anon name)
e.g. $(anon rviz-1). Generates an anonymous id based on name. name itself is a unique identifier: multiple uses of $(anon foo) will create the same “anonymized” name. This is used for name attributes in order to create nodes with anonymous names, as ROS requires nodes to have unique names. For example:

5. $(arg foo)
$(arg foo) evaluates to the value specified by an tag. There must be a corresponding tag in the same launch file that declares the arg.
For example:
Will assign the my_foo argument to the foo parameter.
Another example:Will assign the my_foo argument to the foo parameter.
Another example:

Will launch both the server and client from the example, passing as parameters the value a and b. The resulting launch project can be called as follows:
The resulting launch project can be called as follows:
$ roslaunch beginner_tutorials launch_file.launch a:=1 b:=5

All tags support if and unless attributes, which include or exclude a tag based on the evaluation of a value. “1” and “true” are considered true values. “0” and “false” are considered false values. Other values will error.

TAGs:
1. tag
The tag is the root element of any roslaunch file. Its sole purpose is to act as a container for the other elements.
2. tag
The tag specifies a ROS node that you wish to have launched.
Examples

Launches the “listener1″ node using the listener.py executable from the rospy_tutorials package with the command-line argument –test. If the node dies, it will automatically be respawned.

Launches the bar node from the foo_pkg package. This example uses substitution arguments to pass in a portable reference to baz_pkg/resources/map.pgm.
Attributes includes: pkg=”mypackage”, Package of node. type=”nodetype”, Node type. There must be a corresponding executable with the same name. name=”nodename”, Node name. NOTE: name cannot contain a namespace. Use the ns attribute instead. machine=”machine-name”(optional, see ), Launch node on designated machine. ns=”foo”(optional) ,Start the node in the ‘foo’ namespace. output=”log|screen”(optional), If ‘screen’, stdout/stderr from the node will be sent to the screen. If ‘log’, the stdout/stderr output will be sent to a log file in $ROS_HOME/log, and stderr will continue to be sent to screen. The default is ‘log’.
3. tag
The tag declares a machine that you can run ROS nodes on. You do not need this tag if you are launching all the nodes locally. It is mainly used to declare SSH and ROS environment variable settings for remote machines, though you can also use it to declare information about the local machine.
4. tag
The tag allows you to pass in name remapping arguments to the ROS node that you are launching in a more structured manner than setting the args attribute of a directly.
Example, For example, you are given a node that says it subscribes to the “chatter” topic, but you only have a node that publishes the “hello” topic. They are the same type, and you want to pipe your “hello” topic into the new node which wants “chatter” by simply:
5.tag
Thetag defines a parameter to be set on the Parameter Server.
Examples,
6. tag
The tag enables the use of rosparam YAML files for loading and dumping parameters from the ROS Parameter Server. It can also be used to remove parameters. The tag can be put inside of a tag, in which case the parameter is treated like a private name. The delete and dump commands run before the load command as well as before any other parameters are uploaded to the Parameter Server. delete and dump commands run in the declared order.
Examples
7. The tag
The tag makes it easier to apply settings to a group of nodes. I
8. tag
The tag allows you to create more re-usable and configurable launch files by specifying values that are passed via the command-line, passing in via an , or declared for higher-level files. Args are not global. An arg declaration is specific to a single launch file, much like a local parameter in a method. You must explicitly pass arg values to an included file, much like you would in a method call.
can be used in one of three ways:
, Declares the existence of foo. foo must be passed in either as a command-line argument (if top-level) or via passing (if included).
, Declares foo with a default value. foo can be overriden by command-line argument (if top-level) or via passing (if included).
, Declares foo with constant value. The value for foo cannot be overridden. This usage enables internal parameterization of a launch file without exposing that parameterization at higher levels.
Examples:
my.launch: ## declare var hoge, and assign value, productor

included.launch: ## get value , store t paramserver, consumer

Passing an argument via the command-line:

$ $ roslaunch %YOUR_ROS_PKG% my.launch hoge:=my_new_value

Minimal Example
The following example shows a minimal launch configuration script. It launches a single ‘talker’ node, which is part of the ‘rospy_tutorials’ package. This node will launch on the local machine using the currently configured ROS environment (i.e. ROS_ROOT, etc…).

A Complicated Example

Setting parameters
You can also set parameters on the Parameter Server. These parameters will be stored on the Parameter Server before any nodes are launched.

5 – TIPS FOR LARGE PROJECTS

1. Introduction
Large applications on a robot typically involve several interconnected nodes, each of which have many parameters.
The 2d navigation is a good example. The 2dnav_pr2 application consists of the move_base node itself, localization, ground plane filtering, the base controller, and the map server. Collectively, there are also a few hundred ROS parameters that affect the behavior of these nodes. Finally, there are constraints such as the fact that ground plane filtering should run on the same machine as the tilt laser for efficiency.
A roslaunch file allows us to say all this. Given a running robot, launching the file 2dnav_pr2.launch in the 2dnav_pr2 package will bring up everything required for the robot to navigate. In this tutorial, we’ll go over this launch file and the various features used.
We’d also like roslaunch files to be as reusable as possible. In this case, moving between physically identical robots can be done without changing the launch files at all. Even a change such as moving from the robot to a simulator can be done with only a few changes. We’ll go over how the launch file is structured to make this possible.

2. Top-level organization
Here is the top-level launch file (in “rospack find 2dnav_pr2/move_base/2dnav_pr2.launch”).

This file includes a set of other files. Each of these included files contains nodes and parameters (and possibly nested includes) pertaining to one part of the system, such as localization, sensor processing, and path planning.
Design tip: Top-level launch files should be short, and consist of include’s to other files corresponding to subcomponents of the application, and commonly changed ROS parameters.
This makes it easy to swap out one piece of the system, as we’ll see later.

To run this on the PR2 robot requires bringing up a core, then bringing up a robot-specific launch file such as pre.launch in the pr2_alpha package, and then launching 2dnav_pr2.launch. We could have included a robot launch file here rather than requiring it to be launched separately. That would bring the following tradeoffs:
PRO: We’d have to do one fewer “open new terminal, roslaunch” step.
CON: Launching the robot launch file initiates a calibration phase lasting about a minute long. If the 2dnav_pr2 launch file included the robot launch file, every time we killed the roslaunch (with control-c) and brought it back up, the calibration would happen again.
CON: Some of the 2d navigation nodes require that the calibration already have finished before they start. Roslaunch intentionally does not provide any control on the order or timing of node start up. The ideal solution would be to make nodes work gracefully by waiting till calibration is done, but pending that, putting things in two launch files allows us to launch the robot, wait until calibration is complete, then launch 2dnav.

There is therefore no universal answer on whether or not to split things into multiple launch files. Here, it has been decided to use two different launch files.
Design tip: Be aware of the tradeoffs when deciding how many top-level launch files your application requires.

3. Machine tags and Environment Variables
We would like control over which nodes run on which machines, for load-balancing and bandwidth management. For example, we’d like the amcl node to run on the same machine as the base laser. At the same time, for reusability, we don’t want to hardcode machine names into $ roslaunch files. Roslaunch handles this with ****machine*** tags.

The first include is

The first thing to note about this file is the use of the env substitution argument to use the value of the environment variable ROBOT. For example, doing “$ export ROBOT=pre”
prior to the roslaunch would cause the file pre.machine to be included.
*** Design tip: Use the env substitution argument to allow parts of a launch file to depend on environment variables.

Next, let’s look at an example machine file: pre.machine in the pr2_alpha package.

This file sets up a mapping between logical machine names, “c1” and “c2” in this case, and actual host names, such as “pre2”. It even allows controlling the user you log in as (assuming you have the appropriate ssh credentials).
Once the mapping has been defined, it can be used when launching nodes. For example, the included file config/new_amcl_node.xml in the 2dnav_pr2 package contains the line:

This causes the amcl node to run on machine with logical name c1 (looking at the other launch files, you’ll see that most of the laser sensor processing has been put on this machine).
When running on a new robot, say one known as prf, we just have to change the ROBOT environment variable. The corresponding machine file (prf.machine in the pr2_alpha package) will then be loaded. We can even use this for running on a simulator, by setting ROBOT to sim. Looking at the file sim.machine in the pr2_alpha package, we see that it just maps all logical machine names to localhost.
*** Design tip: Use machine tags to balance load and control which nodes run on the same machine, and consider having the machine file name depend on an environment variable for reusability.

4. Parameters, namespaces, and yaml files
Let’s look at the included file move_base.xml. Here is a portion of this file:

The first included element is a remapping. Move_base is designed to receive odometry on the topic “odom”. In the case of the pr2, odometry is published on the pr2_base_odometry topic, so we remap it.
*** Design tip: Use topic remapping when a given type of information is published on different topics in different situations.
Then is followed by a bunch oftags. Note that these parameters are inside the node element (since they’re before the at the end), so they will be private parameters. For example, the first one sets move_base/controller_frequency to 10.0.
After theelements, there are some elements. These read parameter data in yaml, a format which is human readable and allows complex data structures.
Here’s a portion of the costmap_common_params.yaml file loaded by the first element:
raytrace_range: 3.0
footprint: [[-0.325, -0.325], [-0.325, 0.325], [0.325, 0.325], [0.46, 0.0], [0.325, -0.325]]
inflation_radius: 0.55
We see that yaml allows things like vectors (for the footprint parameter). It also allows putting some parameters into a nested namespace. For example, base_scan_marking/sensor_frame is set to base_laser. Note that these namespaces are relative to the yaml file’s own namespace, which was declared as global_costmap by the ns attribute of the including rosparam element. In turn, since that rosparam was included by the node element, the fully qualified name of the parameter is /move_base/global_costmap/base_scan_marking/sensor_frame.
# BEGIN VOXEL STUFF
observation_sources: base_scan_marking base_scan tilt_scan ground_object_cloud
base_scan_marking: {sensor_frame: base_laser, topic: /base_scan_marking, data_type: PointCloud, expected_update_rate: 0.2,
observation_persistence: 0.0, marking: true, clearing: false, min_obstacle_height: 0.08, max_obstacle_height: 2.0}
We see that yaml allows things like vectors (for the footprint parameter). It also allows putting some parameters into a nested namespace. For example, base_scan_marking/sensor_frame is set to base_laser. Note that these namespaces are relative to the yaml file’s own namespace, which was declared as global_costmap by the ns attribute of the including rosparam element. In turn, since that rosparam was included by the node element, the fully qualified name of the parameter is /move_base/global_costmap/base_scan_marking/sensor_frame.

The next line in move_base.xml is:

This actually includes the exact same yaml file as the line before it. It’s just in a different namespace (the local_costmap namespace is for the trajectory controller, while the global_costmap namespace affects the global navigation planner). This is much nicer than having to retype all the values.

The next line is:

Unlike the previous ones, this element doesn’t have an ns attribute. Thus the yaml file’s namespace is the parent namespace, /move_base.
But take a look at the first few lines of the yaml file itself:
local_costmap:
#Independent settings for the local costmap
publish_voxel_map: true
global_frame: odom_combined
robot_base_frame: base_link
Thus we see that the parameters are in the /move_base/local_costmap namespace after all.
*** Design tip: Yaml files allow parameters with complex types, nested namespaces of parameters, and reusing the same parameter values in multiple places.

5. Reusing launch files
The motivation for many of the tips above was to make reusing launch files in different situations easier. We’ve already seen one example, where the use of the env substitution arg can allow modifying behavior without changing any launch files. There are some situations, though, where that’s inconvenient or impossible. Let’s take a look at the pr2_2dnav_gazebo package. This contains a version of the 2d navigation app, but for use in the Gazebo simulator. For navigation, the only thing that changes is actually that the Gazebo environment we use is based on a different static map, so the map_server node must be loaded with a different argument. We could have used another env substitution here. But that would require the user to set a bunch of environment variables just to be able to roslaunch. Instead, 2dnav gazebo contains its own top level launch file called ‘2dnav-stack-amcl.launch’, shown here (modified slightly for clarity):

The first difference is that, since we know we’re on the simulator, we just use the sim.machine file rather than using a substitution argument.
Second, the line

has been replaced by

The included file in the first case just contained a node declaration as in the second case, but with a different map file.
*** Design tip: To modify a “top-level” aspect of an application, copy the top level launch file and change the portions you need.

6. Parameter overrides
The technique above sometimes becomes inconvenient. Suppose we want to use 2dnav_pr2, but just change the resolution parameter of the local costmap to 0.5. We could just locally change local_costmap_params.yaml. This is the simplest for temporary modifications, but it means we can’t check the modified file back in. We could instead make a copy of local_costmap_params.yaml and modify it. We would then have to change move_base.xml to include the modified yaml file. And then we would have to change 2dnav_pr2.launch to include the modified move_base.xml. This can be time-consuming, and if using version control, we would no longer see changes to the original files. An alternative is to restructure the launch files so that the move_base/local_costmap/resolution parameter is defined in the top-level file 2dnav_pr2.launch, and make a modified version of just that file. This is a good option if we know in advance which parameters are likely to be changed.
Another option is to use roslaunch’s overriding behavior: parameters are set in order (after includes are processed). Thus, we could make a further top-level file that overrides the original resolution:

The main drawback is that this method can make things harder to understand: knowing the actual value that roslaunch sets for a parameter requires tracing through the including roslaunch files. But it does avoid having to make copies of multiple files.
*** Design tip: To modify a deeply nested parameter in a tree of launch files which you cannot change, use roslaunch’s parameter overriding semantics.

7. Roslaunch arguments
As of CTurtle, roslaunch has an argument substitution feature together with tags that allow conditioning parts of the launch file on the value of arguments. This can be a more general and clear way to structure things than the parameter override mechanism or launch file reuse techniques above, at the cost of having to modify the original launch file to specify what the changeable arguments are. See the roslaunch XML documentation.

Design tip: If you can modify the original launch file, it’s often preferable to use roslaunch arguments rather than parameter overriding or copying roslaunch files.

机器人操作系统ROS(17):actionlib进度查询

ROS 里除了基本的msg publisher/Subscriber和Server/Client之外,还有ActionLib 值得注意。
ROS中的服务service是一问一答的形式,你来查询了,我就返给你要的信息。
Actionlib也有服务的概念,但是它不一样的地方是:不是一问一答,而多了一个反馈,它会不断反馈项目进度。

actionlib提供动作(action ROS中表示一些长时间连续性的行为)的编程接口,提供动作执行时的查看状态,终止, 抢占等一系列功能。
如navigation下的move_base, 你设定了目标点,反馈信息可能是机器人在规划路径上的即时位姿,直到机器人到达目标点,返回SUCCEEDED消息。Examples of this include moving the base to a target location, performing a laser scan and returning the resulting point cloud, detecting the handle of a door, etc.

因为move_base会遇到很多有关actionlib的实现,需要先例解actionlib才可以清楚navigation的其他包。
move_base作为navigation的逻辑核心,实现了一个供上层节点调用的action 接口(通过actionlib 实现),即给定坐标信息与相应坐标位置,执行相应的安全导航动作。对于下层控制器,输出为cmd_vel 速度。 它规定了这个navigation的行为。
ROS中的自主移动规划层向上的编程接口一般都是通过这个actionlib。

1 ActionClient, ActionServer
In any large ROS based system, there are cases when someone would like to send a request to a node to perform some task, and also receive a reply to the request. This can currently be achieved via ROS services.

In some cases, however, if the service takes a long time to execute, the user might want the ability to cancel the request during execution or get periodic feedback about how the request is progressing. The actionlib package provides tools to create servers that execute long-running goals that can be preempted. It also provides a client interface in order to send requests to the server.

ActionClient 和 ActionServer 通过 ROS Action Protocol (ROS Action 协议,建立在ROS messages的基础上)来通信。
Client&Server 为用户提供了简单的API,通过函数的调用和回调,用来在client端request一个目标,或者,在server端来执行达成一个目标。下图说明这个机制如何运行:


这个是Client主动,ActionServer被动.

=== a Simple Action Server using the Execute Callback

2 Goal, Feedback, & Result
In order for the client and server to communicate, we need to define a few messages on which they communicate. This is with anaction specification. This defines the Goal, Feedback, and Result messages with which clients and servers communicate:

Goal
To accomplish tasks using actions, we introduce the notion of a goal that can be sent to an ActionServer by an ActionClient. In the case of moving the base, the goal would be a PoseStamped message that contains information about where the robot should move to in the world. For controlling the tilting laser scanner, the goal would contain the scan parameters (min angle, max angle, speed, etc).
Feedback
Feedback provides server implementers a way to tell an ActionClient about the incremental progress of a goal. For moving the base, this might be the robot’s current pose along the path. For controlling the tilting laser scanner, this might be the time left until the scan completes.
Result
A result is sent from the ActionServer to the ActionClient upon completion of the goal. This is different than feedback, since it is sent exactly once. This is extremely useful when the purpose of the action is to provide some sort of information. For move base, the result isn’t very important, but it might contain the final pose of the robot. For controlling the tilting laser scanner, the result might contain a point cloud generated from the requested scan.
.action File
The action specification is defined using a .action file. The .action file has the goal definition, followed by the result definition, followed by the feedback definition, with each section separated by 3 hyphens (—).
These files are placed in a package’s ./action directory, and look extremely similar to a service’s .srv file. An action specification for doing the dishes might look like the following:
./action/DoDishes.action
# Define the goal
uint32 dishwasher_id # Specify which dishwasher we want to use

# Define the result
uint32 total_dishes_cleaned

# Define a feedback message
float32 percent_complete
熟悉Message机制就知道,这个类似,就是定义 action specification的消息数据类型.
Based on this .action file, 6 messages need to be generated in order for the client and server to communicate. This generation can be automatically triggered during the make process.
For the DoDishes.action, the following messages are generated by genaction.py:
DoDishesAction.msg
DoDishesActionGoal.msg
DoDishesActionResult.msg
DoDishesActionFeedback.msg
DoDishesGoal.msg
DoDishesResult.msg
DoDishesFeedback.msg

3. Catkin, Rosbuild
3.1 Catkin
Add the following to your CMakeLists.txt file before catkin_package().
注意你要用 actionlib 的话,记得修改CMakeLists.txt .

find_package(catkin REQUIRED genmsg actionlib_msgs actionlib)
add_action_files(DIRECTORY action FILES DoDishes.action)
generate_messages(DEPENDENCIES actionlib_msgs)
actionlib
actionlib_msgs

3.2 Rosbuild

What following lists some tutorials examples.
4. create a test stack
$ cd ~/catkin_ws/src
$ catkin_create_pkg learning_actionlib actionlib message_generation roscpp rospy std_msgs actionlib_msgs

=== CH 5 – a Simple Action Server using the Execute Callback

5 C++ Example 1: Simple Action Server using the Execute Callback
This tutorial covers using the simple_action_server library to create a Fibonacci action server. This example action server generates a Fibonacci sequence,
the goal is the order of the sequence,
the feedback is the sequence as it is computed,
and the result is the final sequence.

5.1 Creating the Action Messages
Before writing an action it is important to define the goal, result, and feedback messages.
The action messages are generated automatically from the .action file.
This file defines the type and format of the goal, result, and feedback topics for the action.

mkdir ./action
vi ./action/fib.action

#goal definition
int32 order

#result definition
int32[] sequence

#feedback
int32[] sequence

5.2 Change CMakeLists.txt
a few things need to be added to CMakeLists.txt, add the actionlib_msgs package to the find_package macro’s argument like this

vi CMakeLists.txt

**1** find_package macro:
find_package(catkin REQUIRED COMPONENTS actionlib_msgs)

**2**: add_action_files macro
add_action_files(
DIRECTORY action
FILES fib.action
)

**3** generate_messages macro:
generate_messages(
DEPENDENCIES actionlib_msgs std_msgs # Or other packages containing msgs
)

**4** catkin_package macro:
catkin_package(
CATKIN_DEPENDS actionlib_msgs
)

Note: Sometimes you have to setup your package.xml, since we are generating messages you have to declare on the manifest file that at run time you have to generate messages.

**5** You could just insert the follow line:
vi package.xml
actionlib_msgs
actionlib_msgs

**6**
Now, we can automatically generate msg files of your action files, and also see the result:
$ cd ~/catkin_ws
$ catkin_make
$ ls devel/share/mimebot/msg/

fibActionFeedback.msg fibActionGoal.msg fibAction.msg fibActionResult.msg fibFeedback.msg fibGoal.msg fibResult.msg

**7**
Also, we can To manually generate the message files from this file,

$ roscd mimebot
$ rosrun mimebot genaction.py -o msg/ action/fib.action

Generating for action fib

5.3 Writing a Simple Server

$ vi ./src/m_fib_server.cpp

#include
#include
// Include the action library used from implementing simple actions.
#include
// The file generated automatically from the /devel/share/mimebot/msg/fibAction.msg file .
// this action message generated from the fib.action file .

class fibAction
{
protected:
ros::NodeHandle nh_;
//The node handle is constructed and passed into the action server during construction of the action.

actionlib::SimpleActionServer as_;
//The action server is constructed in the constructor of the action
//NodeHandle instance must be created before this line. Otherwise strange error occurs.

std::string action_name_;
//create messages that are used to published feedback/result

mimebot::fibFeedback feedback_;
mimebot::fibResult result_;
//The feedback and result messages are created for publishing in the action.

public:
fibAction(std::string name) :
as_(nh_, name, boost::bind(&fibAction::executeCB, this, _1), false),
action_name_(name) { as_.start(); }
//In the action constructor, an action server is created.
//The action server takes arguments of a node handle, name of the action, and optionally an executeCB.

~fibAction(void)
{
}

//The callback function is passed a pointer to the goal message.
// Note: This is a boost shared pointer, given by appending “ConstPtr” to the end of the goal message type.
void executeCB(const mimebot::fibGoalConstPtr &goal)
{
// helper variables
ros::Rate r(1);
bool success = true;

// push_back the seeds for the fibonacci sequence
feedback_.sequence.clear();
feedback_.sequence.push_back(0);
feedback_.sequence.push_back(1);

// publish info to the console for the user
ROS_INFO(“%s is executing, creating sequence of order %i with seeds %i, %i”, action_name_.c_str(), goal->order, feedback_.sequence[0], feedback_.sequence[1]);

// start executing the action
for(int i=1; i<=goal->order; i++)
{
// check that preempt has not been requested by the client
if (as_.isPreemptRequested() || !ros::ok())
{
ROS_INFO(“%s is Preempted”, action_name_.c_str());
// set the action state to preempted
as_.setPreempted();
success = false;
break;
}
feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]);
// publish the feedback
as_.publishFeedback(feedback_);
// this sleep is not necessary, the sequence is computed at 1 Hz for demonstration purposes
r.sleep();
}

if(success)
{
result_.sequence = feedback_.sequence;
ROS_INFO(“%s is Succeeded”, action_name_.c_str());
// set the action state to succeeded
as_.setSucceeded(result_);
}
}

};

int main(int argc, char** argv)
{
ros::init(argc, argv, “m_fib”);

fibAction fibonacci(“action_fib”);
ros::spin();

return 0;
}

5.4 change CMakeLists.txt

Add the following lines to your CMakeLists.txt file:

add_executable(m_fib_server src/m_fib_server.cpp)
target_link_libraries(m_fib_server ${catkin_LIBRARIES} )
add_dependencies(m_fib_server ${mimebot_EXPORTED_TARGETS})

$ catkin_make

5.5
test
$ rosrun mimebot m_fib_server
to cheak:
$ rostopic list -v

/fib/cancel
/fib/feedback
/fib/goal
/fib/result
/fib/status
or,
$ rqt_graph

=== CH 6 clinet

5.6 Writing Action Client

$ vi mimebot/src/m_fib_client.cpp

#include
#include
//the action library used from implementing simple action clients.
#include
//defines the possible goal states.
#include

int main (int argc, char **argv)
{
ros::init(argc, argv, “m_fib_client”);

// create the action client
// true causes the client to spin its own thread
actionlib::SimpleActionClient ac(“action_fib”, true);
//The action client constructor also takes two arguments, the server name to connect to and a boolean option to automatically spin a thread.
//Here the action client is constructed with the server name and the auto spin option set to true.

ROS_INFO(“Waiting for action server to start.”);
// wait for the action server to start
ac.waitForServer(); //will wait for infinite time
ROS_INFO(“Action server started, sending goal.”);

// send a goal to the action
mimebot::fibGoal goal;
goal.order = 20;
ac.sendGoal(goal);

//wait for the action to return
bool finished_before_timeout = ac.waitForResult(ros::Duration(30.0));

if (finished_before_timeout)
{
actionlib::SimpleClientGoalState state = ac.getState();
ROS_INFO(“Action finished: %s”,state.toString().c_str());
}
else
ROS_INFO(“Action did not finish before the time out.”);

//exit
return 0;
}

5.7 change CMakeLists.txt

add_executable(m_fib_client src/m_fib_client.cpp)

target_link_libraries( m_fib_client ${catkin_LIBRARIES} )
add_dependencies( m_fib_client ${mimebot_EXPORTED_TARGETS})

$catkin_make

5.8 to ckeak
$ rostopic echo /fib/feedback
$ rostopic echo /fib/result
$ rosrun learning_actionlib fibonacci_server
$ rosrun learning_actionlib fibonacci_client

6. Python Example2: Simple Action Server using the Execute Callback
6.1 Writing a Simple Action Server
#! /usr/bin/env python
import roslib; roslib.load_manifest(‘actionlib_tutorials’)
import rospy
import actionlib
import actionlib_tutorials.msg

class FibonacciAction(object):
# create messages that are used to publish feedback/result
_feedback = actionlib_tutorials.msg.FibonacciFeedback()
_result = actionlib_tutorials.msg.FibonacciResult()

def __init__(self, name):
self._action_name = name
self._as = actionlib.SimpleActionServer(self._action_name, actionlib_tutorials.msg.FibonacciAction, execute_cb=self.execute_cb, auto_start = False)
#Here, the SimpleActionServer is created, we pass it a name, an action type, and optionally an execute callback
#Since we’ve specified an execute callback in this example, a thread will be spun for us which allows us to take long running actions in a callback received when a new goal comes in.
self._as.start()

def execute_cb(self, goal):
# helper variables
r = rospy.Rate(1)
success = True

# append the seeds for the fibonacci sequence
self._feedback.sequence = []
self._feedback.sequence.append(0)
self._feedback.sequence.append(1)

# publish info to the console for the user
rospy.loginfo(‘%s: Executing, creating fibonacci sequence of order %i with seeds %i, %i’ % (self._action_name, goal.order, self._feedback.sequence[0], self._feedback.sequence[1]))

# start executing the action
for i in xrange(1, goal.order):
# check that preempt has not been requested by the client
if self._as.is_preempt_requested():
rospy.loginfo(‘%s: Preempted’ % self._action_name)
self._as.set_preempted()
success = False
break
#An important component of an action server is the ability to allow an action client to request that the goal under execution be canceled. When a client requests that the current goal be preempted, the action server should cancel the goal, perform any necessary cleanup, and call the set_preempted function, which signals that the action has been preempted by user request. Here, we’ll check if we’ve been preempted every second. We could, alternatively, receive a callback when a preempt request is received.

self._feedback.sequence.append(self._feedback.sequence[i] + self._feedback.sequence[i-1])
# publish the feedback
self._as.publish_feedback(self._feedback)
# this step is not necessary, the sequence is computed at 1 Hz for demonstration purposes
r.sleep()
#Here, the Fibonacci sequence is put into the feedback variable and then published on the feedback channel provided by the action server. Then, the action continues looping and publishing feedback.

if success:
self._result.sequence = self._feedback.sequence
rospy.loginfo(‘%s: Succeeded’ % self._action_name)
self._as.set_succeeded(self._result)
#Once the action has finished computing the Fibonacci sequence, the action server notifies the action client that the goal is complete by calling set_succeeded.

if __name__ == ‘__main__’:
rospy.init_node(‘fibonacci’)
FibonacciAction(rospy.get_name())
rospy.spin()

6.2 Writing a Simple Action Client
#! /usr/bin/env python
import roslib; roslib.load_manifest(‘actionlib_tutorials’)
import rospy
# Brings in the SimpleActionClient
import actionlib
# Brings in the messages used by the fibonacci action, including the goal message and the result message.
import actionlib_tutorials.msg

def fibonacci_client():
# Creates the SimpleActionClient, passing the type of the action (FibonacciAction) to the constructor.
client = actionlib.SimpleActionClient(‘fibonacci’, actionlib_tutorials.msg.FibonacciAction)
#The action client and server communicate over a set of topics, described in the actionlib protocol. The action name describes the namespace containing these topics, and the action specification message describes what messages should be passed along these topics

# Waits until the action server has started up and started
# listening for goals.
client.wait_for_server()
#Sending goals before the action server comes up would be useless. This line waits until we are connected to the action server.

# Creates a goal to send to the action server.
goal = actionlib_tutorials.msg.FibonacciGoal(order=20)

# Sends the goal to the action server.
client.send_goal(goal)

# Waits for the server to finish performing the action.
client.wait_for_result()

# Prints out the result of executing the action
return client.get_result() # A FibonacciResult

if __name__ == ‘__main__’:
try:
# Initializes a rospy node so that the SimpleActionClient can
# publish and subscribe over ROS.
rospy.init_node(‘fibonacci_client_py’)
result = fibonacci_client()
print “Result:”, ‘, ‘.join([str(n) for n in result.sequence])
except rospy.ROSInterruptException:
print “program interrupted before completion”

6.3 to check
$ rosrun actionlib_tutorials fibonacci_server
$ rosrun actionlib_tutorials fibonacci_client.py
$ rostopic echo fibonacci/feedback

7. C++ Example3: Writing a Simple Action Server using the Goal Callback Method
This tutorial covers using the simple_action_server library to create an averaging action server. This example shows how to use an action to process or react to incoming data from ros nodes. The action server averages data from a ros node, the goal is the number of samples to average, the feedback is the sample number, the sample data, the current average, and current standard deviation, and the result is the average and standard deviation of the requested number of samples.

7.1 Create learning_actionlib/action/Averaging.action
#goal definition
int32 samples

#result definition
float32 mean
float32 std_dev

#feedback
int32 sample
float32 data
float32 mean
float32 std_dev

7.2 manually generate the message files from this file:
$ roscd learning_actionlib
$ rosrun actionlib_msgs genaction.py -o msg/ action/Averaging.action<—-???
or,
automatically generate the message files during the make process, need to add the following to CMakeLists.txt:
find_package(catkin REQUIRED COMPONENTS actionlib std_msgs message_generation)
add_action_files(DIRECTORY action FILES Averaging.action)
generate_messages(DEPENDENCIES std_msgs actionlib_msgs)
and
$ catkin_make.

7.3 nano learning_actionlib/src/averaging_server.cpp

7.4 Add the following line to CMakeLists.txt file:
add_executable(averaging_server src/averaging_server.cpp)
target_link_libraries(averaging_server ${catkin_LIBRARIES})

7.5 catkin_make
7.6 to cheak
$ rosrun learning_actionlib averaging_server

7.7 Writing a Threaded Simple Action Client
$ nano learning_actionlib/src/averaging_client.cpp

7.8 Add the following line to CMakeLists.txt file:
add_executable(averaging_client src/averaging_client.cpp)
target_link_libraries(averaging_client ${catkin_LIBRARIES})
catkin_make

7.9 to check
$ rosrun learning_actionlib averaging_server
$ rosrun learning_actionlib averaging_client

7.10 from other node

4. C++ samples
4.1 C++ ActionClient
4.2 C++ ActionServer
5. Python samples
5.1 Python ActionClient
5.2 Python ActionServer

http://www.cnblogs.com/feixiao5566/p/4757916.html