文章目录
1.时间相关API
为什么要有时间相关API呢?我们使用机器人建图的时候,需要的数据肯定是实时的,不能有延迟。如果我当前位置的信息,几秒后才能接收到,那么是非常危险的!所以有了事件相关API就能较好地解决这些问题!
准备工作:
创建一个功能包
1.1 API_Rate
在前面写的话题通信案例中, 要求话题发布方按照一定的频率发布消息, 我们实现时是通过定时器来控制发布频率的, 其实, 除了定时器之外, ROS2 中还提供了 Rate 类, 通过该类对象也可以控制程序的运行频率。
示例: 周期性输出一段文本。
//1.包含头文件;
#include "rclcpp/rclcpp.hpp"
using namespace std::chrono_literals;//使用该命名空间
//3.自定义节点类;
class MyNode:public rclcpp::Node{
public:
MyNode():Node("time_node_cpp"){
demo_rate();
}
private:
//演示Rate的使用
void demo_rate()
{
//1.创建Rate对象
rclcpp::Rate rate1(500ms);//设置休眠时间,500ms休眠一次
rclcpp::Rate rate2(1);//设置执行频率,1s一次
//2.调用Rate的sleep函数
while(rclcpp::ok())
{
RCLCPP_INFO(this->get_logger(),"RateAPI测试!");
rate1.sleep();
//rate2.sleep();
}
}
};
int main(int argc, char const *argv[])
{
//2.初始化ROS2客户端;
rclcpp::init(argc,argv);
//4.调用spain汉书,并传入节点对象指针;
rclcpp::spin(std::make_shared<MyNode>());
//5.资源释放
rclcpp::shutdown();
return 0;
}
rate1.sleep();//这个就是一秒两次输出日志 rate2.sleep();//这个就是一秒一次输出日志
1.2 API_Time
示例: 创建 Time 对象, 并调用其函数。(时间转化,纳秒与秒转化)
//1.包含头文件;
#include "rclcpp/rclcpp.hpp"
using namespace std::chrono_literals;
//3.自定义节点类;
class MyNode:public rclcpp::Node{
public:
MyNode():Node("time_node_cpp"){
demo_time();
}
private:
//演示Time的使用
void demo_time()
{
//1.创建Time对象
rclcpp::Time t1(500000000L);//传入纳秒,1s=10亿纳秒
rclcpp::Time t2(2,500000000L);//传入秒和纳秒
// rclcpp::Time right_now=this->get_clock()->now();//第一种方式
rclcpp::Time right_now = this->now();//通过节点获取当前时刻,第二种方式
//2.调用Time对象的函数
RCLCPP_INFO(this->get_logger(),"s=%.2f,ns=%ld",t1.seconds(),t1.nanoseconds());
RCLCPP_INFO(this->get_logger(),"s=%.2f,ns=%ld",t2.seconds(),t2.nanoseconds());
RCLCPP_INFO(this->get_logger(),"s=%.2f,ns=%ld",right_now.seconds(),right_now.nanoseconds());
//seconds是以秒获取时刻,nanoseconds是以纳秒获取时刻,纳秒是长整型
}
};
int main(int argc, char const *argv[])
{
//2.初始化ROS2客户端;
rclcpp::init(argc,argv);
//4.调用spain汉书,并传入节点对象指针;
rclcpp::spin(std::make_shared<MyNode>());
//5.资源释放
rclcpp::shutdown();
return 0;
}
1.3 API_Duration
示例: 创建 Duration 对象, 并调用其函数。(时间转化,纳秒与秒转化)
//1.包含头文件;
#include "rclcpp/rclcpp.hpp"
using namespace std::chrono_literals;
//3.自定义节点类;
class MyNode:public rclcpp::Node{
public:
MyNode():Node("time_node_cpp"){
demo_duration();
}
private:
//演示Duration的使用
void demo_duration()
{
//1.创建Duration对象
rclcpp::Duration du1(1s);
rclcpp::Duration du2(2,500000000);
//2.调用函数
RCLCPP_INFO(this->get_logger(),"s=%.2f,ns=%ld",du1.seconds(),du1.nanoseconds());
RCLCPP_INFO(this->get_logger(),"s=%.2f,ns=%ld",du2.seconds(),du2.nanoseconds());
}
};
int main(int argc, char const *argv[])
{
//2.初始化ROS2客户端;
rclcpp::init(argc,argv);
//4.调用spain汉书,并传入节点对象指针;
rclcpp::spin(std::make_shared<MyNode>());
//5.资源释放
rclcpp::shutdown();
return 0;
}
1.4 API_Time和API_Duration的区别
1.5 Time 与 Duration 运算
//1.包含头文件;
#include "rclcpp/rclcpp.hpp"
using namespace std::chrono_literals;
//3.自定义节点类;
class MyNode:public rclcpp::Node{
public:
MyNode():Node("time_node_cpp"){
//demo_time();
//demo_duration();
demo_opt();
}
private:
//演示运算符的使用
void demo_opt()
{
rclcpp::Time t1(10,0);
rclcpp::Time t2(30,0);
rclcpp::Duration du1(8,0);
rclcpp::Duration du2(17,0);
// 比较
RCLCPP_INFO(this->get_logger(),"t1 >= t2 ? %d",t1 >= t2);
RCLCPP_INFO(this->get_logger(),"t1 < t2 ? %d",t1 < t2);
// 数学运算
rclcpp::Time t3 = t2 + du1;
rclcpp::Time t4 = t1 - du1;
rclcpp::Duration du3 = t2 - t1;
RCLCPP_INFO(this->get_logger(), "t3 = %.2f",t3.seconds());
RCLCPP_INFO(this->get_logger(), "t4 = %.2f",t4.seconds());
RCLCPP_INFO(this->get_logger(), "du3 = %.2f",du3.seconds());
RCLCPP_INFO(this->get_logger(),"--------------------------------------");
// 比较
RCLCPP_INFO(this->get_logger(),"du1 >= du2 ? %d", du1 >= du2);
RCLCPP_INFO(this->get_logger(),"du1 < du2 ? %d", du1 < du2);
// 数学运算
rclcpp::Duration du4 = du1 * 3.0;
rclcpp::Duration du5 = du1 + du2;
rclcpp::Duration du6 = du1 - du2;
RCLCPP_INFO(this->get_logger(), "du4 = %.2f",du4.seconds());
RCLCPP_INFO(this->get_logger(), "du5 = %.2f",du5.seconds());
RCLCPP_INFO(this->get_logger(), "du6 = %.2f",du6.seconds());
}
//演示Duration的使用
void demo_duration()
{
//1.创建Duration对象
rclcpp::Duration du1(1s);
rclcpp::Duration du2(2,500000000);
//2.调用函数
RCLCPP_INFO(this->get_logger(),"s=%.2f,ns=%ld",du1.seconds(),du1.nanoseconds());
RCLCPP_INFO(this->get_logger(),"s=%.2f,ns=%ld",du2.seconds(),du2.nanoseconds());
}
//演示Time的使用
void demo_time()
{
//1.创建Time对象
rclcpp::Time t1(500000000L);
rclcpp::Time t2(2,500000000L);
// rclcpp::Time right_now=this->get_clock()->now();
rclcpp::Time right_now = this->now();
//2.调用Time对象的函数
RCLCPP_INFO(this->get_logger(),"s=%.2f,ns=%ld",t1.seconds(),t1.nanoseconds());
RCLCPP_INFO(this->get_logger(),"s=%.2f,ns=%ld",t2.seconds(),t2.nanoseconds());
RCLCPP_INFO(this->get_logger(),"s=%.2f,ns=%ld",right_now.seconds(),right_now.nanoseconds());
}
};
int main(int argc, char const *argv[])
{
//2.初始化ROS2客户端;
rclcpp::init(argc,argv);
//4.调用spain汉书,并传入节点对象指针;
rclcpp::spin(std::make_shared<MyNode>());
//5.资源释放
rclcpp::shutdown();
return 0;
}
2.通信机制工具
一个完整的机器人系统启动之后,其组成是比较复杂的,可能包含十几个、几十个甚至上百个节点,不同的节点可能又包含一个或多个通信对象(话题发布方、话题订阅方、服务端、客户端、动作服务端、动作客户端、参数服务端、参数客户端),通信时还需要使用到各种各样的msg、srv或action接口消息,那么在开发过程中,如何才能方便的获取这些节点、话题、服务、动作、参数以及接口相关的信息呢?
编写通信实现,通信至少涉及到双方,一方编写完毕后,如何验证程序是否可以正常运行呢?
话题通信过程中,发布方程序中设置了消息的发布频率,如何判断实际运行中的发布频率是否和设置的频率一致呢?
这些就取决于我们的通信机制工具了!!!
2.1 命令工具
ROS2中常用的命令如下:
ros2 node:节点相关命令行工具
ros2 interface:接口(msg、srv、action)消息相关的命令行工具
ros2 topic:话题通信相关的命令行工具
ros2 service:服务通信相关的命令行工具
ros2 action:动作通信相关的命令行工具
ros2 param:参数服务相关的命令行工具
关于命令的使用一般都会提供帮助文档,帮助文档的获取方式如下:
①可以通过命令 -h 或 命令 --help的方式查看命令帮助文档,比如:ros2 node -h或 ros2 node --help。
②命令下参数的使用也可以通过命令 参数 -h 或 命令 参数 --help的方式查看帮助文档,比如:ros2 node list -h或 ros2 node list --help。
一些常用的命令功能如下:
2.2 rqt工具箱
rqt工具箱是ROS里面一种可视化工具,使用非常方便!
常用的rqt启动命令有:
方式1:rqt
方式2:ros2 run rqt_gui rqt_gui
预备工作:打开我们的小乌龟和键盘控制
下面简单列举几种功能:
1.查看话题和相关节点信息之间的关联(graph):
2.添加topic插件并发送速度指令控制乌龟运动
3.添加 service 插件并发送请求,在制定位置生成一只乌龟。
4.通过参数插件动态修改乌龟窗体背景颜色。
当然rqt的功能远不仅仅如此!