单纯为了用的时候可以找到,并不详细。
ROS API使用
API官方文档
http://wiki.ros.org/APIs
https://docs.ros.org/en/api/roscpp/html/
1. 初始化-init
argc, argv, name
argc
参数个数, (1+n个,1是运行文件的名字,n是传入的参数)。
argv
参数列表,n个参数会被添加到参数服务器中。
name
节点名称,需要保证其唯一性,不允许包含命名空间。
void init(int &argc, char **argv, const std::string& name, uint32_t options = 0);
终端指定参数到参数服务器
argc
, argv
可以通过在终端启动时添加。
rosrun pkg node _param1:=value1 _param2:=value2
用例
使用以下代码编写cpp文件,Cmake正常编译。
#include "ros/ros.h"
#include "std_msgs/String.h"
int main(int argc, char *argv[])
{
setlocale(LC_ALL, "");
//优化实现,获取命令中的参数
std::stringstream ss;
for (int i = 0; i < argc; i++)
ss << "\n 第" << i << "个参数对应内容为: " << argv[i] << ";";
ROS_INFO_STREAM(ss.str());
ros::init(argc, argv, "erGouzi"); //节点名字唯一
ros::NodeHandle nh;
ros::Publisher client = nh.advertise<std_msgs::String>("fang",10);
return 0;
}
终端运行:
rosrun plumbing_apis demo01_apis_init _length:=2 _width:=5
然后分别运行:
rosparam get /erGouzi/length
rosparam get /erGouzi/width
可以查看到刚刚自己添加的参数已经成功。
options
options
节点启动选项,重名节点启动时,之前的节点会被关闭。
使用ros::init_options::AnonymousName
可以自动为节点添加时间后缀,防止重复。
使用
ros::init(argc, argv, "erGouzi", ros::init_options::AnonymousName);
rosnode list
结果:
/erGouzi_1712628973497673621
/erGouzi_1712628984491861251
Python中
rospy.init_node(name, argv=None, anonymous=False, log_level=None, disable_rostime=False, disable_rosout=False, disable_signals=False, xmlrpc_port=0, tcpros_port=0)
2. 发布-advertise 和 订阅-subscribe
topic, queue_size
topic
发布消息使用的话题
queue_size
等待发送给订阅者的最大消息数量。
template <class M>
Publisher advertise(const std::string& topic, uint32_t queue_size, bool latch = false)
使用:
ros::Publisher pub = nh.advertise<plumbing_msg::Msg>("liaotian", 1000);
ros::Subscriber sub = nh.subscribe("liaotian", 10, doMsg);
pub.publish(msg)
latch
latch (optional)
如果为 true,该话题发布的最后一条消息将被保存,并且后期当有新的订阅者连接时会将该消息发送给订阅者。如果是false,则不保存。
使用场景
通常,如果要发送一个静态的数据(比如地图),不用latch时:要固定频率一直发送(否则新加入的订阅者可能接受不到该数据),浪费资源;使用latch时:保存好数据,当新的订阅者加入时自动发送一次,不浪费资源。
Python中
class Publisher(Topic):
def __init__(self, name, data_class, subscriber_listener=None, tcp_nodelay=False, latch=False, headers=None, queue_size=None):
class Subscriber(Topic):
def __init__(self, name, data_class, callback=None, callback_args=None, queue_size=None, buff_size=DEFAULT_BUFF_SIZE, tcp_nodelay=False):
3. 服务-advertiseService 和 客户-serviceClient
ServiceServer advertiseService(const std::string& service, bool(*srv_func)(MReq&, MRes&))
ServiceClient serviceClient(const std::string& service_name, bool persistent = false,
const M_string& header_values = M_string())
persistent
persistent
标志用于指示服务是否应该保持持久性连接。
如果将此标志设置为True,则服务将保持连接状态,直到调用方显式断开连接为止。这意味着一旦服务被调用,连接将保持打开状态,直到调用方决定关闭它,而不是在每次请求之间重新建立连接。
使用:
ros::ServiceServer server = nh.advertiseService("AddInts",doReq);
ros::ServiceClient client = nh.serviceClient<demo03_server_client::AddInts>("AddInts");
client.waitForExistence();
client.call(srv);
Python中
class Service(ServiceImpl):
def __init__(self, name, service_class, handler, buff_size=DEFAULT_BUFF_SIZE, error_handler=None):
class ServiceProxy(_Service):
def __init__(self, name, service_class, persistent=False, headers=None):
4. 回旋函数-spin&spinOnce
为处理回调函数而使用。
spin
spin
:一直检查队列中的回调函数并执行然后继续检查,会堵塞到当前行。
spinOnce
spinOnce
:运行到spinOnce时,将队列中所有回调函数都执行完(不是只执行队列里的最后一个),然后继续执行其他代码,不会堵塞。
5. 时间戳-Time
获取的是以1970年01月01日为起始时间到现在的时间差。
使用时,必须提前调用ros::NodeHandle nh
初始化相关函数。
时刻
当前时刻
ros::Time now = ros::Time::now();
double now_time = now.toSec();
ROS_INFO("当前时刻: %.2f", now.toSec());
ROS_INFO("当前时刻-秒部分: %d", now.sec);
ROS_INFO("当前时刻-纳秒部分: %d", now.nsec);
设置固定时刻
就是使用构造函数,有两种
ros::Time t1(100, 35); // 参数1:秒数 参数2:纳秒
ros::Time t2(100.35);//就是上面的两者相加
ROS_INFO("t1时刻: %.2f", t1.toSec());
ROS_INFO("t2时刻: %.2f", t2.toSec());
持续时间
ROS_INFO("当前时刻:%.2f",ros::Time::now().toSec());
ros::Duration du(10);//持续10秒钟,参数是double类型的,以秒为单位
du.sleep();//按照指定的持续时间休眠
ROS_INFO("持续时间:%.2f",du.toSec());//将持续时间换算成秒
ROS_INFO("当前时刻:%.2f",ros::Time::now().toSec());
时刻与持续时间的运算
包含 :
- 时刻与持续时间的加减。
- 持续时间与持续时间的加减。
没有时刻与时刻的加减。
ROS_INFO("时间运算");
ros::Time now = ros::Time::now();
ros::Duration du1(10);
ros::Duration du2(20);
ROS_INFO("当前时刻:%.2f",now.toSec());
//1.time 与 duration 运算
ros::Time after_now = now + du1;
ros::Time before_now = now - du1;
ROS_INFO("当前时刻之后:%.2f",after_now.toSec());
ROS_INFO("当前时刻之前:%.2f",before_now.toSec());
//2.duration 之间相互运算
ros::Duration du3 = du1 + du2;
ros::Duration du4 = du1 - du2;
ROS_INFO("du3 = %.2f",du3.toSec());
ROS_INFO("du4 = %.2f",du4.toSec());
//PS: time 与 time 不可以运算
// ros::Time nn = now + before_now;//异常
睡眠
Rate
ros::Rate rate(10); //指定频率
rate.sleep(); //睡眠时间为: 1/10=0.1s
Duration
ros::Duration du(10);//持续10秒钟
du.sleep();//睡眠时间为: 10s
定时器
period
时间间隔
callback
回调函数
oneshot
如果设置为 true,只执行一次回调函数,设置为 false, 就循环执行。
autostart
如果为true,返回已经启动的定时器,设置为 false,需要手动启动。
Timer createTimer(Duration period, const TimerCallback& callback, bool oneshot = false, bool autostart = true) const;
启动 timer.start();
停止 timer.stop();
用例
void print_time(const ros::TimerEvent event)
{
std::time_t current_time = ros::Time::now().toSec();
struct std::tm* local_time = localtime(¤t_time);
char buffer[80];
std::strftime(buffer, 80, "%Y-%m-%d %H:%M:%S", local_time);
std::cout << "Current Time: " << buffer << std::endl;
}
// main函数下
ros::Timer timer = nh.createTimer(ros::Duration(2), print_time);
ros::spin(); //处理回调函数
5. 节点状态
节点状态判断
ros::ok();
true:节点还健在;
false:节点已经停止。
关闭节点函数
ros::shutdown();
python中是 rospy.signal_shutdown()
。
6.日志函数
ROS_DEBUG("hello,DEBUG"); //不会输出在控制台,调试时才显示
ROS_INFO("hello,INFO"); //默认白色字体
ROS_WARN("Hello,WARN"); //默认黄色字体
ROS_ERROR("hello,ERROR");//默认红色字体
ROS_FATAL("hello,FATAL");//默认红色字体