ROS的C++接口总结
节点初始化与关闭
节点初始化
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
作用
- RAII节点自启动与关闭
ros::NodeHandle nh;
- 简化命名空间
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树
- 广播
from ‘world’ to turtle_name
br.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "world", turtle_name));
- 侦听
from ‘/turtle1’ to ‘/turtle2’
listener.lookupTransform("/turtle2", "/turtle1", ros::Time(0), transform);
- 时空
TF缓存
时延
实现原理
- xmlrpc
- PollSet/PollManager
poll()
- Connections
- Transports
- TransportTCP
- TransportUDP
- Transports