文章目录
API:应用程序编程接口
常用API(C++版本)
1. 初始化
ros::init(argc,argv,“erGouZi”,ros::init_options::AnonymousName)
作用: ROS初始化函数
参数:
1. argc ----- 封装实参个数(n+1)第1个是文件自身
2. argv ----- 封装参数数组(字符串数组)
3. name ----- 为节点命名(唯一性)
4. options -- 节点启动选项
返回值:void
使用细节:
1. argc 与 argv的使用
如果按照ROS中的特定格式传入实参,那么ROS可以加以使用,比如用来设置全局参数,给节点重命名
2. options的使用
节点名称需要保证唯一,会导致一个问题:同一个节点不能重复启动
问题:ROS中有重名的节点启动时,之前的节点就会被关闭
需求:特定场景下,需要一个节点多次启动且能正常运行,怎么办?
(场景:比如安装2个摄像头用的节点)
解决:设置启动项 ros::init_options::AnonymousName
当创建ROS节点时,会在用户自定义的节点名称后缀随机数,从而避免重名问题
2. 话题与服务相关对象
ros::Publisher pub = nh.advertise<std_msgs::String>(“fang”,10,true)
作用:创建发布者对象
模板:被发布的消息的类型
参数:
1. 话题名称
2. 队列长度
3. latch(可选) 如果设置为true,会保存发布方的最后一条消息,并且
新的订阅对象连接到发布方时,发布方会将消息发送给订阅方
使用:
latch设置为true的作用?
以静态地图为例,
方案1:可以使用固定频率发送地图数据,但效率低
方案2:可以将地图发布对象的latch设置为true,并且发布方只发布一次数据,每当订阅者连接时,
就可以将地图数据发送给订阅者(只发送一次),提高数据的发送效率。
3. 回旋函数
ros::spin() && ros::spinOnce
- 相同点:二者都用于处理回调函数
- 不同点:ros::spin() 是进入了循环执行回调函数,而 ros::spinOnce() 只会执行一次回调函数(没有循环),在ros::spin() 后的语句不会执行到,而 ros::spinOnce() 后的语句可以执行
4. 时间
4.1 时刻
获取时刻,或是设置指定时刻
C++代码
#include"ros/ros.h"
/*
需求: 演示时间相关的操作(获取当前时刻 + 设置制定时刻)
实现:
1. 准备(头文件、节点初始化、NodeHandle创建)
2. 获取当前时刻
3. 设置指定时刻
*/
int main(int argc, char *argv[])
{
// 1. 准备(头文件、节点初始化、NodeHandle创建)
setlocale(LC_ALL,"");
ros::init(argc,argv,"hello_time");
ros::NodeHandle nh;// 注意:必须。否则会导致时间API调用失败(再NodeHandle会初始化时间操作)
// 2. 获取当前时刻
// now函数会将当前时刻封装并返回
// 当前时刻:now 被调用执行的那一刻
// 参考系:1970年1月1日 00:00:00
ros::Time right_now = ros::Time::now();//距离参考系逝去的时间
ROS_INFO("当前时刻:%.2f",right_now.toSec());// 将逝去的时间总长以秒为单位计算,dounle类型
ROS_INFO("当前时刻:%d",right_now.sec);// 将逝去的时间总长以秒为单位计算,整数类型
// 3. 设置指定时刻
ros::Time t1(20,312345678);//构造函数,意思是距离参考系过去20秒,以及312345678纳秒
ros::Time t2(100.35);//浮点型B
ROS_INFO("t1 = %.2f",t1.toSec());
ROS_INFO("t2 = %.2f",t2.toSec());
return 0;
}
Python代码
if __name__ == "__main__":
# 需求1: 演示时间相关操作(获取当前时刻 + 设置指定时刻)
rospy.init_node("hello_time")
# 获取时刻
right_now = rospy.Time.now() # 获取当前时刻(1.now函数被执行的那一刻 2.参考1970年01月01日00:00)并封装成对象
rospy.loginfo("当前时刻:%.2f",right_now.to_sec()) # 浮点
rospy.loginfo("当前时刻:%.2f",right_now.secs) # 整型 secs后面没有()
# 设置指定
time1 = rospy.Time(100.5) # 将时间封装成time对象,将1970年01月01日00:00逝去100.5秒
time2 = rospy.Time(100,312345678) # 后面是纳秒,将1970年01月01日00:00逝去100.312345678秒
rospy.loginfo("指定时刻1:%.2f",time1.to_sec()) # 浮点
rospy.loginfo("指定时刻1:%.2f",time2.to_sec()) # 浮点
# 从某个时间值获取时间对象
time3 = rospy.Time.from_sec(210.12)
rospy.loginfo("指定时刻1:%.2f",time3.to_sec()) # 浮点
4.2 持续时间
C++实现
ROS_INFO("------------------持续时间--------------");
ros::Time start = ros::Time::now();
ROS_INFO("开始休眠: %.2f",start.toSec());
ros::Duration du(4.5); //持续时间封装了4.5秒
du.sleep();//睡眠4.5s
ros::Time end = ros::Time::now();
ROS_INFO("休眠结束:%.2f",end.toSec());
pyhton实现
# 需求2: 程序执行中停顿5秒
rospy.loginfo("休眠前-------------------")
# 1. 封装一个持续时间对象(5秒)
du = rospy.Duration(5,0) # 第二个位置纳秒
# 2. 再将持续时间休眠
rospy.sleep(du)
rospy.loginfo("休眠后-------------------")
4.3 持续时间与运算
1. 时刻与持续时间可以执行加减
2. 持续时间之间可以可以执行加减
3. 时刻之间值可以相减,不可以相加
C++实现
// 时刻与持续时间运算
// 1. 获取开始执行的时刻
ros::Time begin = ros::Time::now();
// 2. 模拟运行时间(N秒)
ros::Duration du1(5);
// 3. 计算结束时刻 = 开始+持续时间
ros::Time stop = begin + du1; // 也可以用 -
ROS_INFO("开始时刻:%.2f",begin.toSec());
ROS_INFO("结束时刻:%.2f",stop.toSec());
// 时刻与时刻运算
// ros::Time sum = begin + stop;不可以相加
ros::Duration du2 = begin - stop;//-5
ROS_INFO("时刻相减:%.2f",du2.toSec());
// 持续时间与持续时间的运算
ros::Duration du3 = du1 + du2;// 0
ros::Duration du4 = du1 - du2;// 10
ROS_INFO("du1 + du2 = %.2f",du3.toSec());
ROS_INFO("du1 - du2 = %.2f",du4.toSec());
Python实现
# 需求3: 获取程序开始执行的限制,且一直持续运行的时间,计算程序结束的时间
# 1. 获取一个时刻 t1
t1 = rospy.Time.now()
# 2. 设置一个持续时间 du1
du1 = rospy.Duration(5)
# 3. 结束时刻 t2 = t1 + du1
t2 = t1 + du1
rospy.loginfo("开始时刻:%.2f",t1.to_sec())
rospy.loginfo("结束时刻:%.2f",t2.to_sec())
du2 = du + du1
rospy.loginfo("持续时间相加:%.2f",du2.to_sec())
4.4 运行频率和定时器
注意:
创建: nh.createTimer()
参数1: 时间间隔
参数2: 回调函数(时间事件 TimerEvent)
参数3: 是否只执行1次
参数4: 是否自动启动(当设置false时,需要手动调用 timer.start())
定时器启动后: ros::spin()
/*
ros::Timer createTimer(ros::Duration period, // 时间间隔 --- 1
const ros::TimerCallback &callback, // 回调函数 --- 封装业务
bool oneshot = false, // 是否为1次性,dalse的话每隔1秒中执行1次回调函数,循环执行
bool autostart = true) // 自动启动
*/
// ros::Timer timer = nh.createTimer(ros::Duration(1),cb);//每隔1秒执行一次回调函数
// ros::Timer timer = nh.createTimer(ros::Duration(1),cb,true);//true只执行一次回调函数
ros::Timer timer = nh.createTimer(ros::Duration(1),cb,false,false);//false不会自动启动
timer.start();//手动启动
ros::spin();//需要回旋
定时器Python实现
def doMsg(event):
rospy.loginfo("+++++++++++++")
rospy.loginfo("调用回调函数的时刻:%.2f",event.current_real.to_sec()) # current_real 是rospy.Time类型
# 需求4: 创建定时器,实现类似于 ros::Rate 的功能(隔某个时间间隔执行某个操作)
"""
@param period: desired period between callbacks 回调函数之间调用时间间隔
@type period: rospy.Duration
@param callback: callback to be called
@type callback: function taking rospy.TimerEvent
@param oneshot: if True, fire only once, otherwise fire continuously until shutdown is called [default: False]
@type oneshot: bool
"""
# timer = rospy.Timer(rospy.Duration(2),doMsg,True) # 创建一个定时器对象,每个2秒钟执行一次回调
timer = rospy.Timer(rospy.Duration(2),doMsg) # 创建一个定时器对象,每个2秒钟执行一次回调
rospy.spin()
4.5 总的程序
C++实现
#include"ros/ros.h"
/*
需求1: 演示时间相关的操作(获取当前时刻 + 设置制定时刻)
实现:
1. 准备(头文件、节点初始化、NodeHandle创建)
2. 获取当前时刻
3. 设置指定时刻
需求2: 程序执行中停顿5秒
实现:
1. 创建持续时间对象
2. 休眠
需求3: 已知程序开始运行的时刻和程序运行的时间,求运行结束的时刻
实现:
1. 获取开始执行的时刻
2. 模拟运行时间(N秒)
3. 计算结束时刻 = 开始+持续时间
注意:
1. 时刻与持续时间可以执行加减
2. 持续时间之间可以可以执行加减
3. 时刻之间值可以相减,不可以相加
需求4: 每隔1秒中,在控制台输出一段文本。
实现:
策略1:ros::Rate()
策略2:定时器
注意:
创建: nh.createTimer()
参数1: 时间间隔
参数2: 回调函数(时间事件 TimerEvent)
参数3: 是否只执行1次
参数4: 是否自动启动(当设置false时,需要手动调用 timer.start())
定时器启动后: ros::spin()
*/
//回调函数
void cb(const ros::TimerEvent& event){
ROS_INFO("----------");
ROS_INFO("函数被调用的时刻:%.2f",event.current_real.toSec());
}
int main(int argc, char *argv[])
{
// 需求1
// 1. 准备(头文件、节点初始化、NodeHandle创建)
setlocale(LC_ALL,"");
ros::init(argc,argv,"hello_time");
ros::NodeHandle nh;// 注意:必须。否则会导致时间API调用失败(再NodeHandle会初始化时间操作)
// 2. 获取当前时刻
// now函数会将当前时刻封装并返回
// 当前时刻:now 被调用执行的那一刻
// 参考系:1970年1月1日 00:00:00
ros::Time right_now = ros::Time::now();//距离参考系逝去的时间
ROS_INFO("当前时刻:%.2f",right_now.toSec());// 将逝去的时间总长以秒为单位计算,dounle类型
ROS_INFO("当前时刻:%d",right_now.sec);// 将逝去的时间总长以秒为单位计算,整数类型
// 3. 设置指定时刻
ros::Time t1(20,312345678);//构造函数,意思是距离参考系过去20秒,以及312345678纳秒
ros::Time t2(100.35);//浮点型B
ROS_INFO("t1 = %.2f",t1.toSec());
ROS_INFO("t2 = %.2f",t2.toSec());
// 需求2
ROS_INFO("------------------持续时间--------------");
ros::Time start = ros::Time::now();
ROS_INFO("开始休眠: %.2f",start.toSec());
ros::Duration du(4.5); //持续时间封装了4.5秒
du.sleep();//睡眠4.5s
ros::Time end = ros::Time::now();
ROS_INFO("休眠结束:%.2f",end.toSec());
// 需求3
ROS_INFO("------------------时间运算--------------");
// 时刻与持续时间运算
// 1. 获取开始执行的时刻
ros::Time begin = ros::Time::now();
// 2. 模拟运行时间(N秒)
ros::Duration du1(5);
// 3. 计算结束时刻 = 开始+持续时间
ros::Time stop = begin + du1; // 也可以用 -
ROS_INFO("开始时刻:%.2f",begin.toSec());
ROS_INFO("结束时刻:%.2f",stop.toSec());
// 时刻与时刻运算
// ros::Time sum = begin + stop;不可以相加
ros::Duration du2 = begin - stop;//-5
ROS_INFO("时刻相减:%.2f",du2.toSec());
// 持续时间与持续时间的运算
ros::Duration du3 = du1 + du2;// 0
ros::Duration du4 = du1 - du2;// 10
ROS_INFO("du1 + du2 = %.2f",du3.toSec());
ROS_INFO("du1 - du2 = %.2f",du4.toSec());
//需求4
ROS_INFO("------------------定时器--------------");
/*
ros::Timer createTimer(ros::Duration period, // 时间间隔 --- 1
const ros::TimerCallback &callback, // 回调函数 --- 封装业务
bool oneshot = false, // 是否为1次性,dalse的话每隔1秒中执行1次回调函数,循环执行
bool autostart = true) // 自动启动
*/
// ros::Timer timer = nh.createTimer(ros::Duration(1),cb);//每隔1秒执行一次回调函数
// ros::Timer timer = nh.createTimer(ros::Duration(1),cb,true);//true只执行一次回调函数
ros::Timer timer = nh.createTimer(ros::Duration(1),cb,false,false);//false不会自动启动
timer.start();//手动启动
ros::spin();//需要回旋
return 0;
}
Python实现
5 日志
C++实现
#include"ros/ros.h"
/*
ROS中的日志:
演示不同级别日志的使用
*/
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
ros::init(argc,argv,"hello_log");
ros::NodeHandle nh;
// 日志输出
ROS_DEBUG("调试信息");//不会打印在控制台
ROS_INFO("一般信息");
ROS_WARN("警告信息");
ROS_ERROR("错误信息");
ROS_FATAL("严重错误");
return 0;
}
Python实现
#! /usr/bin/env python
import rospy
if __name__ == "__main__":
# 演示日志函数
rospy.init_node("hello_log")
rospy.logdebug("DEBUG消息...")
rospy.loginfo("INFO消息...")
rospy.logwarn("WARN消息...")
rospy.logerr("ERROR消息...")
rospy.logfatal("FATAL消息...")
6. 自定义头文件调用
头文件hello.h
#ifndef _HELLO_H
#define _HELLO_H
/*
声明 namespace
|-- class
|-- run
*/
namespace hello_ns{
class MyHello{
public:
void run();
};
}
#endif
主要文件
#include"ros/ros.h"
#include"plumbing_head/hello.h" // c_cpp_properties配置路径
namespace hello_ns{
void MyHello::run(){
ROS_INFO("run 函数执行.....");
}
}
int main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
ros::init(argc,argv,"hello_head");
// 函数调用
hello_ns::MyHello myHello;
myHello.run();
return 0;
}