提炼总结—ROS2机器人开发(第5章)(下)

写在最前面的话
为什么做该博客?该博客的特点是什么?
随着DeepSeek、ChatGPT等AI技术的崛起,促使机器人技术发展到了新的高度,诞生了宇树科技、特斯拉为代表的人形机器人,四足机器人等等,越来越多的科技巨头涌入机器人赛道,行业对于相关人才的需求也随之达到了顶峰。本博客的内容是替你阅读所有关于机器人的经典书籍,采用书籍瘦身计划,帮你提炼出核心内容,采用最通俗易懂的语言来解释原理,将书读薄。大大缩短学习时间,助你快速成为机器人时代的佼佼者。

文章目录
写在最前面的话
一、书籍介绍
二、第5章 ROS2常用开发工具(提炼总结)
5.3节 C++中的地图坐标系变换(提炼总结)
5.3.1节 通过C++发布静态TF(提炼总结)
5.3.2节 通过C++发布动态TF(提炼总结)
5.3.3节 通过C++查询TF关系(提炼总结)
5.4节 常用可视化工具rqt与RViz(提炼总结)
5.4.1节 GUI框架rqt(提炼总结)
5.4.2节 数据可视化工具RViz(提炼总结)
5.5节 数据记录工具ros2 bag(提炼总结)
5.6节 ROS2基础之Git进阶(提炼总结)
5.6.1节 查看修改内容(提炼总结)
5.6.2节 学会撤销代码(提炼总结)
5.6.3节 进阶掌握Git分支(提炼总结)
5.7节 小结与点评(提炼总结)
一、书籍介绍
《ROS2机器人开发 从入门到实践》是一本从零基础到实战落地的机器人开发指南,通过"基础理论+工具详解+项目实战"的三阶学习路径,带你掌握机器人操作系统ROS2核心架构。书中不仅包含通信机制、URDF建模等必备知识,更有SLAM导航、机械臂控制等12个工业级案例,配合Git代码库和仿真环境配置指南,帮助开发者快速实现从算法仿真到真机部署的完整闭环。无论是学生、工程师还是科研人员,都能通过本书构建系统的ROS2开发能力,抢占机器人技术前沿阵地。

二、第5章 ROS2常用开发工具(提炼总结)
5.3节 C++中的地图坐标系变换(提炼总结)
目标点在地图与移动机器人之间坐标转换的问题

已知map到base_link之间的关系,map到target_point之间的关系,求target_point和base_link之间的关系
5.3.1节 通过C++发布静态TF(提炼总结)
采用静态TF发布map和target_point之间的关系
1、新建chapt5文件夹,新建chapt5/chapt5_ws/src,在终端输入代码创建功能包

ros2 pkg create demo_cpp_tf --build-type ament_cmake --dependencies tf2 tf2_ros geometry_msgs tf2_geometry_msgs --license Apache-2.0
1
2、在src/demo_cpp_tf/src下新建static_tf_broadcaster.cpp,编写如下代码:

include

include "geometry_msgs/msg/transform_stamped.hpp"

include "rclcpp/rclcpp.hpp"

include "tf2/LinearMath/Quaternion.h"

include "tf2_ros/static_transform_broadcaster.h"

include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"

class StaticTFBroadcaster : public rclcpp::Node
{
public:
StaticTFBroadcaster()
: Node("tf_broadcaster_node")
{
broadcaster_ = std::make_shared<tf2_ros::StaticTransformBroadcaster>(this);
this -> publish_tf();
}

void publish_tf()
{
geometry_msgs::msg::TransformStamped transform;
transform.header.stamp = this->get_clock()->now();
transform.header.frame_id = "map";
transform.child_frame_id = "target_point";
transform.transform.translation.x = 5.0;
transform.transform.translation.y = 3.0;
transform.transform.translation.z = 0.0;
tf2::Quaternion quat;
quat.setRPY(0, 0, 60*M_PI/180);
transform.transform.rotation = tf2::toMsg(quat);
broadcaster_->sendTransform(transform);
}

private:
std::shared_ptr<tf2_ros::StaticTransformBroadcaster> broadcaster_;
};

int main(int argc, char** argv)
{
rclcpp::init(argc, argv);
auto node = std::make_shared();
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
3、在CMakeLists对static_tf_broadcaster进行注册

add_executable(static_tf_broadcaster src/static_tf_broadcaster.cpp)
ament_target_dependencies(static_tf_broadcaster rclcpp tf2 tf2_ros geometry_msgs tf2_geometry_msgs)
install(TARGETS static_tf_broadcaster DESTINATION lib/${PROJECT_NAME})
1
2
3
4、在chapt5_ws目录下运行如下代码,构建功能包

colcon build
1
5、在chapt5_ws目录下,添加环境变量

source install/setup.bash
1
6、在chapt5_ws目录下,运行节点

ros2 run demo_cpp_tf static_tf_broadcaster
1
7、新建一个终端,输入下面命令,来查看坐标变换的结果

ros2 run tf2_ros tf2_echo map target_point
1

5.3.2节 通过C++发布动态TF(提炼总结)
1、在src/demo_cpp_tf/src下新建dynamic_tf_broadcaster.cpp,编写如下代码:

include

include "geometry_msgs/msg/transform_stamped.hpp"

include "rclcpp/rclcpp.hpp"

include "tf2/LinearMath/Quaternion.h"

include "tf2_ros/transform_broadcaster.h"

include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"

include

using namespace std::chrono_literals;

class DynamicTFBroadcaster : public rclcpp::Node
{
public:
DynamicTFBroadcaster()
: Node("dynamic_tf_broadcaster")
{
tf_broadcaster_ = std::make_unique<tf2_ros::TransformBroadcaster>(this);
timer_ = create_wall_timer(10ms, std::bind(&DynamicTFBroadcaster::publishTransform, this));
}

void publishTransform()
{
geometry_msgs::msg::TransformStamped transform;
transform.header.stamp = this->get_clock()->now();
transform.header.frame_id = "map";
transform.child_frame_id = "base_link";
transform.transform.translation.x = 2.0;
transform.transform.translation.y = 3.0;
transform.transform.translation.z = 0.0;
tf2::Quaternion quat;
quat.setRPY(0.0, 0.0, 30*M_PI/180);
transform.transform.rotation = tf2::toMsg(quat);
tf_broadcaster_->sendTransform(transform);
}

private:
std::shared_ptr<tf2_ros::TransformBroadcaster> tf_broadcaster_;
rclcpp::TimerBase::SharedPtr timer_;
};

int main(int argc, char ** argv)
{
rclcpp::init(argc, argv);
auto node = std::make_shared();
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2、在CMakeLists对dynamic_tf_broadcaster进行注册

add_executable(dynamic_tf_broadcaster src/dynamic_tf_broadcaster.cpp)
ament_target_dependencies(dynamic_tf_broadcaster rclcpp tf2 tf2_ros geometry_msgs tf2_geometry_msgs)
install(TARGETS dynamic_tf_broadcaster DESTINATION lib/${PROJECT_NAME})
1
2
3
3、在chapt5_ws目录下运行如下代码,构建功能包

colcon build
1
4、在chapt5_ws目录下,添加环境变量

source install/setup.bash
1
5、新建一个终端,输入下面命令,运行静态和动态坐标变换节点

ros2 run demo_cpp_tf static_tf_broadcaster
1
ros2 run demo_cpp_tf dynamic_tf_broadcaster
1
6、在chapt5_ws目录下,运行节点

ros2 run demo_cpp_tf dynamic_tf_broadcaster
1

5.3.3节 通过C++查询TF关系(提炼总结)
1、在src/demo_cpp_tf/src下新建tf_listener.cpp,编写如下代码:

include

include "geometry_msgs/msg/transform_stamped.hpp"

include "rclcpp/rclcpp.hpp"

include "tf2/LinearMath/Quaternion.h"

include "tf2/utils.h"

include "tf2_ros/transform_listener.h"

include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"

include "tf2_ros/buffer.h"

include

using namespace std::chrono_literals;

class TFListener : public rclcpp::Node
{
public:
TFListener() : Node("tf_listener")
{
buffer_ = std::make_shared<tf2_ros::Buffer>(this->get_clock());
listener_ = std::make_shared<tf2_ros::TransformListener>(*buffer_,this);
timer_ = this->create_wall_timer(5s, std::bind(&TFListener::getTransform, this));
}

void getTransform()
{
try
{
const auto transform = buffer_->lookupTransform("base_link", "target_point", this->get_clock()->now(),rclcpp::Duration::from_seconds(1.0f));
const auto &translation = transform.transform.translation;
const auto &rotation = transform.transform.rotation;
double yaw,pitch,roll;
tf2::getEulerYPR(rotation,yaw,pitch,roll);
RCLCPP_INFO(get_logger(),"平移分量:{%f ,%f ,%f}",translation.x,translation.y,translation.z);
RCLCPP_INFO(get_logger(),"旋转分量:{%f ,%f ,%f}",yaw,pitch,roll);
}
catch(tf2::TransformException &ex)
{
RCLCPP_WARN(get_logger(),"无法获取转换关系:%s",ex.what());

}

}

private:
std::shared_ptr<tf2_ros::Buffer> buffer_;
std::shared_ptr<tf2_ros::TransformListener> listener_;
rclcpp::TimerBase::SharedPtr timer_;
};

int main(int argc, char * argv[])
{
rclcpp::init(argc, argv);
auto node = std::make_shared();
rclcpp::spin(node);
rclcpp::shutdown();
return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42

posted @ 2025-06-24 16:51  爷很困扰  阅读(66)  评论(0)    收藏  举报