ros

advertisement
What is ROS?
• Robot Operating System
• ROS essentially provides two things:
– A set of tools that are generally useful for
controlling robots
• E.g. Interfaces to sensors, general-purpose algorithms,
etc.
– A communication framework to allow different
pieces of your robot brain to talk to one another
Intro to ROS Nodes
cam_data subscriber
cam_data publisher
cam_data subscriber
ROS
$ roscore
... logging to ~/.ros/log/9cf88ce4-b14d-11df-8a75-00251148e8cf/roslaunch-machine_name13039.log
Checking log directory for disk usage. This may take awhile.
Press Ctrl-C to interrupt
Done checking log file disk usage. Usage is <1GB.
… blah blah blah
Master
rosout
ROS
$ rosrun package1 first-node
Note: run this in a
new terminal
window
Master
Advertise topic1
rosout
first-node
ROS
$ rosrun package2 second-node
Note: run this in a
new terminal
window
Master
Subscribe to topic1
rosout
first-node
second-node
ROS
$ rosrun package2 second-node
Note: run this in a
new terminal
window
Master
Master connects topic1 publisher to topic1
subscriber
rosout
first-node
second-node
ROS
$ rosnode list
/rosout
/first-node
/second-node
Master
topic1
rosout
first-node
second-node
ROS
$ rostopic list
/rosout
/rosout_agg
/topic1
Master
topic1
rosout
first-node
second-node
ROS commands
• roscore : Run this first; starts the Master and some other
essential ROS stuff
• rosrun [package-name] [node-name] : Use this to start a
ROS node
• rosnode :
– rosnode list : List all currently running nodes
– rosnode info [node-name] : Get more info about a
particular node
– rosnode -h : Learn about more things rosnode can do
• rostopic :
– rostopic list : List all topics currently published
– rostopic echo : See the messages being published to a
particular topic
– rostopic -h : Learn about more things rostopic can do
ROS commands
• roslaunch [package-name] [launch-file-name] : Reads a
.launch file, which contains instructions for running
multiple nodes, and doing fancy things like passing
parameters to nodes, renaming topics, etc.
<launch>
<node name="listener-1" pkg="rospy_tutorials" type="listener" />
<node name="listener-2" pkg="rospy_tutorials" type="listener" args="-foo arg2" />
<node name="listener-3" pkg="rospy_tutorials" type="listener" respawn="true" />
<group ns="wg2">
<remap from="chatter" to="hello"/>
<node pkg="rospy_tutorials" type="listener" name="listener" args="--test" />
<node pkg="rospy_tutorials" type="talker" name="talker">
<param name="talker_1_param" value="a value" />
<remap from="chatter" to="hello-1"/>
<env name="ENV_EXAMPLE" value="some value" />
</node>
</group>
</launch>
ROS Skeleton
#include "ros/ros.h"
int main (int argc, char **argv)
{
ros::init(argc, argv, “name");
ros::NodeHandle n;
ros::Rate loop_rate(10);
while (ros::ok())
{
/* Body of event
loop goes here */
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
Line-by-Line Breakdown
#include "ros/ros.h"
int main (int argc, char **argv)
{
ros::init(argc, argv, “name");
ros::NodeHandle n;
ros::Rate loop_rate(10);
while (ros::ok())
{
/* Body of event
loop goes here */
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
• Include the ROS library
Line-by-Line Breakdown
#include "ros/ros.h"
int main (int argc, char **argv)
{
ros::init(argc, argv, “name");
ros::NodeHandle n;
ros::Rate loop_rate(10);
while (ros::ok())
{
/* Body of event
loop goes here */
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
• Program execution
always starts at “main”
• main gets passed
command line
arguments (argc, argv),
which you are required
to pass into ros::init so it
can handle them
appropriately
Line-by-Line Breakdown
#include "ros/ros.h"
int main (int argc, char **argv)
{
ros::init(argc, argv, “name");
ros::NodeHandle n;
ros::Rate loop_rate(10);
while (ros::ok())
{
/* Body of event
loop goes here */
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
• ros:: is a namespace; a
collection of related
functions, data, etc. that
are all packaged together
• Anything in this
namespace has to be
accessed by prefixing it
with ros::
• ros::init (initialize) must be
called before any other
ROS functions; it expects
to be passed main’s
command line arguments
(argc, argv) and the name
of the current node
Line-by-Line Breakdown
#include "ros/ros.h"
int main (int argc, char **argv)
{
ros::init(argc, argv, “name");
ros::NodeHandle n;
ros::Rate loop_rate(10);
while (ros::ok())
{
/* Body of event
loop goes here */
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
• ros::NodeHandle is a class
which allows us to
communicate with the
ROS system
• You must create a
NodeHandle object in
order to properly initialize
and register your ROS
node; when the handle
goes out of scope at the
end of the program, it will
automatically cleanup
after itself
• In the body of your ROS
node, a NodeHandle can
also be used to advertise
or subscribe to topics
Line-by-Line Breakdown
#include "ros/ros.h"
int main (int argc, char **argv)
{
ros::init(argc, argv, “name");
ros::NodeHandle n;
ros::Rate loop_rate(10);
while (ros::ok())
{
/* Body of event
loop goes here */
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
• The main body of a ROS
program is a loop
• The loop keeps running as
long as this ROS node
hasn’t been asked to
shutdown (i.e. as long as
ros::ok() returns true)
• At a high level, a typical
loop might look like this:
– Do some work
– Publish results
– Handle any incoming
messages
– Sleep for a little while, then
repeat
Line-by-Line Breakdown
#include "ros/ros.h"
int main (int argc, char **argv)
{
ros::init(argc, argv, “name");
ros::NodeHandle n;
ros::Rate loop_rate(10);
while (ros::ok())
{
/* Body of event
loop goes here */
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
• ros::spinOnce() checks
to see if there are any
new incoming messages
from other ROS nodes,
and if so, it invokes
callbacks to handle
them appropriately
• We haven’t subscribed
to any topics in this
example, but we’ll see
shortly how this works
Line-by-Line Breakdown
#include "ros/ros.h"
int main (int argc, char **argv)
{
ros::init(argc, argv, “name");
ros::NodeHandle n;
ros::Rate loop_rate(10);
while (ros::ok())
{
/* Body of event
loop goes here */
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
• ros::Rate is essentially a
timer class that helps to
keep your main loop running
at a reasonable frequency
• We first declare
loop_rate(10), which is a
10Hz timer
• At the end of our main loop,
we call loop_rate.sleep(); if
our loop took less than 0.1s
(1/10th of a second),
loop_rate.sleep() will wait
until the full 0.1s has passed
• This way, our main loop
always runs at a (roughly)
consistent frequency
Now, let’s subscribe to a topic
ROS Subscriber
#include "ros/ros.h"
int main (int argc, char **argv)
{
ros::init(argc, argv, “name");
ros::NodeHandle n;
ros::Subscriber sub =
n.subscribe(“topic1", 1000,
callbackFunction);
ros::Rate loop_rate(10);
while (ros::ok())
{
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
• Recall, `n` is our NodeHandle
• Subscribe to a topic using
n.subscribe(...)
– “topic1” is the name of the
topic to subscribe to
– 1000 is the number of incoming
messages to hold on to before
deleting some (so, if we cannot
process messages fast enough,
and get more than 1000
messages behind, we will start
dropping old messages)
– callbackFunction is the name of
the function to invoke when a
new message is received
• n.subscribe(…) returns a
ros::Subscriber object; as
long as we hold on to this
object, we will remain
subscribed to “topic1”
ROS Subscriber
// somewhere else in the program …
void callbackFunction(const std_msgs::String::ConstPtr& msg)
{
printf("I heard: [%s]", msg->data.c_str());
}
• This function will be invoked whenever a new “topic1” message is
processed by ros::spinOnce()
• Note the signature of the function: it returns void, and it accepts a
single parameter “msg”, which is a pointer to the message received
– The type of “msg” will naturally vary, depending on the type of
messages that you are subscribed to. In our case, messages
published to “topic1” are string messages, and have type
std_msgs::String
– Note this is not the same thing as a C++ string object; it is a ROS
message which contains a C++ string
Common std_msgs
Message Type Include
Callback signature
Usage
std_msgs::String #include
“std_msgs/String.h”
void callback(
const::std_msgs::String::ConstPtr &
msg)
string data = msg->data
std_msgs::Bool
#include
“std_msgs/Bool.h”
void callback(
const::std_msgs::Bool::ConstPtr &
msg)
bool data = msg->data
std_msgs::Int32
#include
“std_msgs/Int32.h”
void callback(
const::std_msgs::Int32::ConstPtr &
msg)
int data = msg->data
std_msgs::
Float64
#include “std_msgs/ void callback(
double data = msg->data
Float64.h”
const::std_msgs::Float64::ConstPtr &
msg)
Let’s publish to a topic
ROS Publisher
#include "ros/ros.h“
int main (int argc, char **argv)
{
/* … blah blah blah … */
ros::Publisher pub =
n.advertise<std_msgs::String>
(“topic1”, 1000);
ros::Rate loop_rate(10);
while (ros::ok())
{
std_msgs::String msg;
msg.data = “Foobar”;
pub.publish(msg);
ros::spinOnce();
loop_rate.sleep();
}
return 0;
}
• Advertise a topic using
n.advertise(...)
– Unlike with subscribers, where the
type of the message can be inferred
from the callback function, we need
to explicitly tell ROS what type of
message to expect using <> triangle
brackets
– “topic1” is the name of the topic to
advertise
– 1000 is the number of outgoing
messages to hold on to before
deleting some (so, if we cannot
send messages fast enough, and get
more than 1000 messages behind,
we will start dropping old
messages)
• n.advertise(…) returns a
ros::Publisher object; we send
a message by calling its
.publish(…) method and
passing in a ROS message of
the appropriate type
Okay, we’ve got a complete
(trivial) program – let’s build it!
ROS Package
workspace
ROS Package
workspace
art
ROS Package
art
localplanner
ucontroller
artsystem
imu
ROS Package
localplanner
src
include
CMakeLists.txt
manifest.xml
bin
ROS Package
Source files go in
here
localplanner
src
include
CMakeLists.txt
manifest.xml
bin
ROS Package
Header files go in
here
localplanner
src
include
CMakeLists.txt
manifest.xml
bin
ROS Package
Executables will
be built here
localplanner
src
include
CMakeLists.txt
manifest.xml
bin
ROS Package
Build instructions
go here
localplanner
src
include
CMakeLists.txt
manifest.xml
bin
ROS Package
CMakeLists.txt
cmake_minimum_required(VERSION 2.4.6)
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
# This is a comment
rosbuild_init()
rosbuild_gen_msg()
rosbuild_add_executable(localplanner src/main.cpp)
ROS Package
CMakeLists.txt
cmake_minimum_required(VERSION
2.4.6)
You don’t have to worry about
most of this junk …
include($ENV{ROS_ROOT}/core/rosbuild/rosbuild.cmake)
But this line is important. ROS doesn’t magically know
# This is awhere
comment
your source files are and which ones you want to
package into an executable. So you need to say
rosbuild_init()
rosbuild_add_executable(executable_name source.cpp)
rosbuild_gen_msg()
or
rosbuild_add_executable(executable_name source1.cpp
source2.cpp source3.cpp)
rosbuild_add_executable(localplanner
src/main.cpp)
ROS Package
localplanner
src
include
CMakeLists.txt
manifest.xml
bin
ROS Package
localplanner
Package description
goes here
src
include
CMakeLists.txt
manifest.xml
bin
ROS Package
manifest.xml
<package>
<description brief=“localplanner”>
Local Planner
</description>
<author>Your Name Here</author>
<license>BSD</license>
<review status=“unreviewed” notes=“”/>
<url>http://ros.org/wiki/localplanner</url>
<depend package=“roscpp”/>
<depend package=“artsystem”/>
<depend package=“nav_msgs”/>
<depend package=“ucontroller”/>
</package>
ROS Package
manifest.xml
<package>
<description
You needbrief=“localplanner”>
to list your dependencies here! So
Local Planner
if you #include
something, and ROS is
</description>
complaining,
one
of the first things that you
<author>Your
Name
Here</author>
<license>BSD</license>
should check is whether you need to add
<review
status=“unreviewed”
notes=“”/>
another
dependency to
the manifest.
<url>http://ros.org/wiki/localplanner</url>
<depend package=“roscpp”/>
<depend package=“artsystem”/>
<depend package=“nav_msgs”/>
<depend package=“ucontroller”/>
</package>
roscd
$ roscd localplanner
in general, roscd [package-name]
ROS will find the
specified package and
will change your
working directory to
be the top-level
package directory
localplanner
src
include
CMakeLists manifest
bin
rosmake
$ rosmake localplanner
in general, rosmake [package-name]
or, when in a package directory, just rosmake
ROS will build the specified package
Output of rosmake
$ rosmake localplanner
[ rosmake ] rosmake starting …
[ rosmake ] Packages requested are: [‘localplanner’]
[ rosmake ] Logging into directory /home/sandro/.ros/rosmake/rosmake_output20130921-135115
[ rosmake ] Expanded args [‘localplanner’] to:
[‘localplanner’]
[ rosmake-0] Starting >>> roslang [ make ]
[ rosmake-1] Starting >>> geometry_msgs [ make ]
… blah blah blah …
[ rosmake-0 ] Finished <<< ucontroller [PASS] [ 1.53 seconds ]
[ rosmake-0] Finished <<< localplanner [PASS] [ 1.02 seconds ]
[ rosmake ] Results:
[ rosmake ] Built 8 packages with 0 failures.
[ rosmake ] Summary output to directory
[ rosmake ] /home/sandro/.ros/rosmake/rosmake_output-20130921-135115
Output of rosmake
$ rosmake localplanner
[ rosmake ] rosmake starting …
[ rosmake ] Packages requested are: [‘localplanner’]
[ rosmake ] Logging into directory /home/sandro/.ros/rosmake/rosmake_output20130921-135115
[ rosmake ] Expanded args [‘localplanner’]
to:
You could potentially
see a lot of stuff here,
[‘localplanner’]
because
actually goes and builds
[ rosmake-0] Starting >>> roslang
[ makerosmake
]
[ rosmake-1] Starting >>> geometry_msgs
make ]
all of your [package’s
dependencies for you.
… blah blah blah …
[ rosmake-0 ] Finished <<< ucontroller [PASS] [ 1.53 seconds ]
[ rosmake-0] Finished <<< localplanner [PASS] [ 1.02 seconds ]
[ rosmake ] Results:
[ rosmake ] Built 8 packages with 0 failures.
[ rosmake ] Summary output to directory
[ rosmake ] /home/sandro/.ros/rosmake/rosmake_output-20130921-135115
Output of rosmake
$ rosmake localplanner
[ rosmake ] rosmake starting …
[ rosmake ] Packages requested are: [‘localplanner’]
[ rosmake ] Logging into directory /home/sandro/.ros/rosmake/rosmake_output20130921-135115
[ rosmake ] Expanded args [‘localplanner’]
to: that rosmake successfully
[PASS] means
[‘localplanner’]
built[ make
a package.
[FAIL] means there were
[ rosmake-0] Starting >>> roslang
]
[ rosmake-1] Starting >>> geometry_msgs
errors. [ make ]
… blah blah blah …
[ rosmake-0 ] Finished <<< ucontroller [PASS] [ 1.53 seconds ]
[ rosmake-0] Finished <<< localplanner [PASS] [ 1.02 seconds ]
[ rosmake ] Results:
[ rosmake ] Built 8 packages with 0 failures.
[ rosmake ] Summary output to directory
[ rosmake ] /home/sandro/.ros/rosmake/rosmake_output-20130921-135115
Output of rosmake
$ rosmake localplanner
[ rosmake ] rosmake starting …
[ rosmake ] Packages requested are: [‘localplanner’]
[ rosmake ] Logging into directory /home/sandro/.ros/rosmake/rosmake_output20130921-135115
[ rosmake ] Expanded args [‘localplanner’] to:
[‘localplanner’]
[ rosmake-0] Starting >>> roslang [ make ]
[ rosmake-1] Starting >>> geometry_msgs [ make ]
0 failures is what you’re looking for
(obviously). If there were failures, you’ll
[ rosmake-0 ] Finished <<< ucontroller [PASS] [ 1.53 seconds ]
also see a list of error messages.
… blah blah blah …
[ rosmake-0] Finished <<< localplanner [PASS] [ 1.02 seconds ]
[ rosmake ] Results:
[ rosmake ] Built 8 packages with 0 failures.
[ rosmake ] Summary output to directory
[ rosmake ] /home/sandro/.ros/rosmake/rosmake_output-20130921-135115
Download