节点初始化与关闭

节点初始化

ros::init(argc, argv, "my_node_name");

// or

ros::init(argc, argv, "my_node_name", ros::init_options::AnonymousName);

启动

ros::NodeHandle nh;

// or

ros::start();
...
ros::shutdown();

关闭

ros::shutdown();
// By default roscpp also installs a SIGINT handler which will detect Ctrl-C and automatically shutdown for you.

while (ros::ok())
{
  ...
}

// or

ros::isShuttingDown();

基础知识

消息类型生成

package_name/msg/Foo.msg $\to$ package_name::Foo

package_name/srv/Foo.srv $\to$ package_name::Foo

发布与订阅

发布

ros::Publisher pub = nh.advertise<std_msgs::String>("topic_name", 5);
std_msgs::String str;
str.data = "hello world";
pub.publish(str);

节点内收发

ros::Publisher pub = nh.advertise<std_msgs::String>("topic_name", 5);
std_msgs::StringPtr str(new std_msgs::String);
str->data = "hello world";
pub.publish(str);

发布选项

template<class M>
ros::Publisher advertise(const std::string& topic, uint32_t queue_size, bool latch = false);

ros::Publisher采用引用计数。

publish()采用队列和异步。

订阅

void callback(const std_msgs::StringConstPtr& str)
{
...
}

...
ros::Subscriber sub = nh.subscribe("my_topic", 1, callback);

订阅选项

template<class M>
ros::Subscriber subscribe(const std::string& topic, uint32_t queue_size, <callback, which may involve multiple arguments>, const ros::TransportHints& transport_hints = ros::TransportHints());

回调

void callback(const boost::shared_ptr<Message const>&);

回调类型:函数

void callback(const std_msgs::StringConstPtr& str)
{
...
}

...
ros::Subscriber sub = nh.subscribe("my_topic", 1, callback);

回调类型:类的方法

void Foo::callback(const std_msgs::StringConstPtr& message)
{
}

...
Foo foo_object;
ros::Subscriber sub = nh.subscribe("my_topic", 1, &Foo::callback, &foo_object);

回调类型:函数对象

class Foo
{
public:
  void operator()(const std_msgs::StringConstPtr& message)
  {
  }
};

ros::Subscriber sub = nh.subscribe<std_msgs::String>("my_topic", 1, Foo());

Transport Hints[?]

ros::Subscriber sub = nh.subscribe("my_topic", 1, callback, ros::TransportHints().unreliable());

服务

my_package/srv/Foo.srv $\to$ my_package::Foo, my_package::Foo::Request, my_package::Foo::Response

数据结构

namespace my_package
{
    struct Foo
    {
        class Request
        {
            ...
        };

        class Response
        {
            ...
        };

        Request request;
        Response response;
    }; 
}

订阅服务

// "bare" way:
//remember that ros::init(...) must have been called
my_package::Foo foo;
...
if (ros::service::call("my_service_name", foo))
{
  ...
}

// "handle" way:
ros::ServiceClient client = nh.serviceClient<my_package::Foo>("my_service_name");
my_package::Foo foo;
...
if (client.call(foo))
{
  ...
}

参数服务器

ros::NodeHandle::getParam()读取参数

ros::NodeHandle nh;
std::string global_name, relative_name, default_param;
if (nh.getParam("/global_name", global_name))
{
  ...
}

if (nh.getParam("relative_name", relative_name))
{
...
}

// Default value version
nh.param<std::string>("default_param", default_param, "default_value");

ros::param::get()读取参数

std::string global_name, relative_name, default_param;
if (ros::param::get("/global_name", global_name))
{
  ...
}

if (ros::param::get("relative_name", relative_name))
{
...
}

// Default value version
ros::param::param<std::string>("default_param", default_param, "default_value");

ros::NodeHandle::setParam()设置参数

ros::NodeHandle nh;
nh.setParam("/global_param", 5);
nh.setParam("relative_param", "my_string");
nh.setParam("bool_param", false);

ros::param::set()设置参数

ros::param::set("/global_param", 5);
ros::param::set("relative_param", "my_string");
ros::param::set("bool_param", false);

检查参数是否存在

ros::NodeHandle nh;
if (nh.hasParam("my_param"))
{
  ...
}

// or

if (ros::param::has("my_param"))
{
  ...
}

删除参数

ros::NodeHandle nh;
nh.deleteParam("my_param");

// or

ros::param::del("my_param");

定时器

用于定期执行任务

ros::Timer timer = nh.createTimer(ros::Duration(0.1), timerCallback);

ros::NodeHandle

作用

  1. RAII节点自启动与关闭ros::NodeHandle nh;
  2. 简化命名空间ros::NodeHandle nh("my_namespace");

回调与轮询(Callbacks and Spinning)

单线程轮询

ros::init(argc, argv, "my_node");
ros::NodeHandle nh;
ros::Subscriber sub = nh.subscribe(...);
...
ros::spin();

// or

ros::Rate r(10);
while (should_continue)
{
  ... do some work, publish some messages, etc. ...
  ros::spinOnce();
  r.sleep();
}
#include <ros/callback_queue.h>
ros::NodeHandle n;
while (ros::ok())
{
  ros::getGlobalCallbackQueue()->callAvailable(ros::WallDuration(0.1));
}

// or

#include <ros/callback_queue.h>
ros::getGlobalCallbackQueue()->callAvailable(ros::WallDuration(0));

多线程轮询

ros::MultiThreadedSpinner spinner(4); // Use 4 threads
spinner.spin(); // spin() will not return until the node has been shutdown

// or

ros::AsyncSpinner spinner(4); // Use 4 threads
spinner.start();
ros::waitForShutdown();

回调队列

CallbackQueue::callAvailable()

CallbackQueue::callOne()

日志

#include <ros/console.h>
ROS_DEBUG("Hello %s", "World");
ROS_DEBUG_STREAM("Hello " << "World");
  • DEBUG
  • INFO
  • WARN
  • ERROR
  • FATAL

读取名字和命名空间

ros::this_node::getName()

ros::this_node::getNamespace()

时间与时刻

ros::Time::now()

ros::Time a_little_after_the_beginning(0.001);
ros::Duration five_seconds(5.0);

TF树

  1. 广播

from ‘world’ to turtle_name

br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name));
  1. 侦听

from ‘/turtle1’ to ‘/turtle2’

listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform);
  1. 时空

TF缓存

时延

实现原理

  • xmlrpc
  • PollSet/PollManager
    • poll()
  • Connections
    • Transports
      • TransportTCP
      • TransportUDP