一、tf坐标变换
1.静态坐标变换
功能实现:发布方:发布世界坐标系和子坐标系之间的关系,以及转换的方法
订阅方:订阅接受发布方的消息,利用订阅到的方法转化坐标
第一步:创建功能包
catkin_create_pkg tf01_static roscpp rospy std_msgs tf2 tf2_ros tf2_geometry_msgs geometry_msgs
第二步:CMakelist文件编写
cmake_minimum_required(VERSION 3.0.2)
project(tf01_static)
find_package(catkin REQUIRED COMPONENTS
geometry_msgs
roscpp
rospy
std_msgs
tf2
tf2_geometry_msgs
tf2_ros
)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES tf01_static
# CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs tf2 tf2_geometry_msgs tf2_ros
# DEPENDS system_lib
)
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
add_executable(tf01_static src/tf01_static.cpp)
add_dependencies(tf01_static ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(tf01_static
${catkin_LIBRARIES}
)
第三步:编写cpp文件
publish.cpp
# include "ros/ros.h"
# include "tf2_ros/static_transform_broadcaster.h"//创建静态坐标转换广播器
# include "geometry_msgs/TransformStamped.h"//创建坐标系信息
# include "tf2/LinearMath/Quaternion.h" //设置四元数
int main(int argc, char* argv[])
{
setlocale(LC_ALL, "");
ros::init(argc, argv, "tf2_static");
ros::NodeHandle n;
//创建静态坐标转换广播器
tf2_ros::StaticTransformBroadcaster broadcaster;
//创建坐标系信息
geometry_msgs::TransformStamped ts;
//设置头信息
ts.header.seq = 100;//头信息
ts.header.stamp = ros::Time::now();//时间戳
ts.header.frame_id = "base_link";//被参考的坐标系
//设置子级坐标系
ts.child_frame_id = "laser";
//设置子级相对于父级的偏移量
ts.transform.translation.x = 0.2;
ts.transform.translation.y = 0.0;
ts.transform.translation.z = 0.5;
//设置四元数
tf2::Quaternion qtn;//利用欧拉角转换
qtn.setRPY(0,0,0);//设置的欧拉角,即相对的偏移俯仰和翻滚,数值都为弧度值
//将欧拉角转化为四元数
ts.transform.rotation.x = qtn.getX();
ts.transform.rotation.y = qtn.getY();
ts.transform.rotation.z = qtn.getZ();
ts.transform.rotation.w = qtn.getW();
//广播器发布坐标信息
broadcaster.sendTransform(ts);
ros::spin();
return 0;
}
sub.cpp
# include "ros/ros.h"
# include "tf2_ros/transform_listener.h"//创建订阅对象
# include "tf2_ros/buffer.h"//订阅的数据实现缓存
# include "geometry_msgs/PointStamped.h"//创建一个坐标点数据
# include "tf2_geometry_msgs/tf2_geometry_msgs.h"//转换过程中用到自己封装的消息
int main (int argc, char* argv[])
{
setlocale(LC_ALL, "");
ros::init(argc, argv, "tf01_static_sub");
ros::NodeHandle n;
//创建订阅对象
//创建一个buffer缓存
tf2_ros::Buffer buffer;
//创建监听对象
tf2_ros::TransformListener listener(buffer);
//创建一个坐标点数据
geometry_msgs::PointStamped ps;
ps.header.frame_id = "laser";
ps.header.stamp = ros::Time::now();
ps.point.x = 2.0;
ps.point.y = 3.0;
ps.point.z = 5.0;
//添加休眠,防止初始时刻出现异常,比如发布方坐标关系还没有准备好
//ros::Duration(2).sleep();//这个的代码功能和下面的try的功能是一样的
//执行转换算法
ros::Rate rate(10);
while (ros::ok())
{
try//检测是否订阅到话题消息,防止发布方的坐标关系还没有准备好
{
//核心代码转化
geometry_msgs::PointStamped ps_out;
//buffer.transform(ps,"base_link")//实现坐标点的转化,第一个参数是原始坐标系,第二个参数是相对与哪一个坐标实现转换,转化后的坐标给ps_out
ps_out = buffer.transform(ps,"base_link");
ROS_INFO("转换后的坐标值是:(%.2f,%.2f,%.2f),参考坐标系:%s",ps_out.point.x,ps_out.point.y,ps_out.point.z,ps_out.header.frame_id.c_str());
rate.sleep();
ros::spinOnce();
}
catch(const std::exception& e)
{
ROS_INFO("Error:%s",e.what());
}
}
return 0;
}
第四步:打开rviz运行
2.动态坐标变换
功能实现:发布方:发布世界坐标系和小乌龟动态坐标系之间的关系,以及转换方法
订阅方:订阅接受发布方的消息,已知一个相对于小乌龟坐标系的坐标,转换为相对于世界坐标系的坐标
第一步:第一步:创建功能包
catkin_create_pkg geometry_msgs roscpp rospy std_msgs tf2 tf2_geometry_msgs tf2_ros turtlesim
第二步:CMakelist文件编写
cmake_minimum_required(VERSION 3.0.2)
project(tf01_dynamic)
find_package(catkin REQUIRED COMPONENTS
geometry_msgs
roscpp
rospy
std_msgs
tf2
tf2_geometry_msgs
tf2_ros
turtlesim
)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES tf01_dynamic
# CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs tf2 tf2_geometry_msgs tf2_ros turtlesim
# DEPENDS system_lib
)
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
add_executable(tf01_dynamic_pub src/tf01_dynamic_pub.cpp)
add_executable(tf01_dynamic_sub src/tf01_dynamic_sub.cpp)
add_dependencies(tf01_dynamic_pub ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
add_dependencies(tf01_dynamic_sub ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(tf01_dynamic_pub
${catkin_LIBRARIES}
)
target_link_libraries(tf01_dynamic_sub
${catkin_LIBRARIES}
)
第三步:编写发布者
# include "ros/ros.h"
# include "turtlesim/Pose.h"//乌龟的位子信息
# include "tf2_ros/transform_broadcaster.h"//发布坐标关系
# include "geometry_msgs/TransformStamped.h"//发布的坐标信息类型
# include "tf2/LinearMath/Quaternion.h"//欧拉角
void callback(const turtlesim::Pose::ConstPtr& pose)
{
//获取位姿并发布
//创建TF发布对象
static tf2_ros::TransformBroadcaster pub;
//组织发布数据
geometry_msgs::TransformStamped ts;
ts.header.frame_id = "world";
ts.header.stamp = ros::Time::now();
ts.child_frame_id = "turtle1";
//坐标偏移量设置
ts.transform.translation.x = pose->x;
ts.transform.translation.y = pose->y;
ts.transform.translation.z = 0;
//坐标系四元数
tf2::Quaternion qtn;
qtn.setRPY(0,0,pose->theta);//乌龟的欧拉角
ts.transform.rotation.x = qtn.getX();
ts.transform.rotation.y = qtn.getY();
ts.transform.rotation.z = qtn.getZ();
ts.transform.rotation.w = qtn.getW();
//发布
pub.sendTransform(ts);
}
int main (int argc, char* argv[])
{
setlocale(LC_ALL,"");
ros::init(argc,argv,"dynamic_pub");
ros::NodeHandle n;
//创建订阅对象,订阅乌龟位姿话题
ros::Subscriber sub = n.subscribe("/turtle1/pose",100,callback);
ros::spin();
return 0;
}
第四步:编写订阅者
# include "ros/ros.h"
# include "tf2_ros/transform_listener.h"
# include "tf2_ros/buffer.h"
# include "geometry_msgs/PointStamped.h"
# include "tf2_geometry_msgs/tf2_geometry_msgs.h"//坐标点转换需要的头文件
int main (int argc, char* argv[])
{
setlocale(LC_ALL, "");
ros::init(argc, argv, "tf01_static_sub");
ros::NodeHandle n;
//创建订阅对象
//创建一个buffer缓存
tf2_ros::Buffer buffer;
//创建监听对象
tf2_ros::TransformListener listener(buffer);
//创建一个坐标点数据
geometry_msgs::PointStamped ps;
ps.header.frame_id = "turtle1";
ps.header.stamp = ros::Time(0.0);//动态坐标变换不能用ros::Time::now()
ps.point.x = 2.0;
ps.point.y = 3.0;
ps.point.z = 5.0;
//执行转换算法
ros::Rate rate(10);
while (ros::ok)
{
try//检测是否订阅到话题消息
{
//核心代码转化
geometry_msgs::PointStamped ps_out;
ps_out = buffer.transform(ps,"world");
ROS_INFO("转换后的坐标值是:(%.2f,%.2f,%.2f),参考坐标系:%s",ps_out.point.x,ps_out.point.y,ps_out.point.z,ps_out.header.frame_id.c_str());
rate.sleep();
ros::spinOnce();
}
catch(const std::exception& e)
{
ROS_INFO("Error:%s",e.what());
}
}
return 0;
}
3.多坐标变换
功能实现:launch文件:发布son1坐标系和son2坐标系相对于世界坐标系的位置关系即对应的坐标转换方法
订阅方:订阅话题信息,找到son01坐标系和son2坐标系之间的关系,已知一个坐标在son1中的坐标,转换为在son2中的坐标
launch文件:
<launch>
<node pkg="tf2_ros" type="static_transform_publisher" name="son1" args="5 0 0 0 0 0 /world /son1" output="screen">
<node pkg="tf2_ros" type="static_transform_publisher" name="son2" args="3 0 0 0 0 0 /world /son2" output="screen">
</launch>
第一步:
catkin_create_pkg tf01_many geometry_msgs roscpp rospy std_msgs tf2 tf2_geometry_msgs tf2_ros
第二步:CMakelist
cmake_minimum_required(VERSION 3.0.2)
project(tf01_many)
find_package(catkin REQUIRED COMPONENTS
geometry_msgs
roscpp
rospy
std_msgs
tf2
tf2_geometry_msgs
tf2_ros
)
catkin_package(
# INCLUDE_DIRS include
# LIBRARIES tf01_many
# CATKIN_DEPENDS geometry_msgs roscpp rospy std_msgs tf2 tf2_geometry_msgs tf2_ros
# DEPENDS system_lib
)
include_directories(
# include
${catkin_INCLUDE_DIRS}
)
add_executable(tf01_many_sub src/tf01_many_sub.cpp)
add_dependencies(tf01_many_sub ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(tf01_many_sub
${catkin_LIBRARIES}
)
第四步:cpp文件
# include "ros/ros.h"
# include "tf2_ros/transform_listener.h"
# include "tf2_ros/buffer.h"
# include "geometry_msgs/PointStamped.h"
# include "tf2_geometry_msgs/tf2_geometry_msgs.h"
# include "geometry_msgs/TransformStamped.h"
int main(int argc, char* argv[])
{
setlocale(LC_ALL,"");
ros::init(argc, argv, "tfs_sub");
ros::NodeHandle n;
//创建订阅对象
tf2_ros::Buffer buffer;
tf2_ros::TransformListener sub(buffer);
//编写解析逻辑
//创建坐标点
geometry_msgs::PointStamped psAtSon1;
psAtSon1.header.stamp = ros::Time::now();
psAtSon1.header.frame_id = "son1";
psAtSon1.point.x = 1.0;
psAtSon1.point.y = 2.0;
psAtSon1.point.z = 3.0;
ros::Rate rate(10);
while (ros::ok())
{
try
{
//计算是son1和son2的关系,TransformStamped函数可以解析多坐标系统中任意两个坐标之间的位置关系
geometry_msgs::TransformStamped son1ToSon2 = buffer.lookupTransform("son2","son1",ros::Time(0));
ROS_INFO("son1相对于son2的信息:父级:%s,子级:%s 偏移量(%.2f,%.2f,%.2f)",
son1ToSon2.header.frame_id.c_str(),
son1ToSon2.child_frame_id.c_str(),
son1ToSon2.transform.translation.x,
son1ToSon2.transform.translation.y,
son1ToSon2.transform.translation.z);
//计算son1中的某个点在son2中的坐标值
geometry_msgs::PointStamped psAtSon2 = buffer.transform(psAtSon1,"son2");
ROS_INFO("坐标点在Son2中的值是(%.2f, %.2f,%.2f)",
psAtSon2.point.x,
psAtSon2.point.y,
psAtSon2.point.z
);
}
catch(const std::exception& e)
{
ROS_INFO("Error:%s", e.what());
}
}
return 0;
}
4.tf2坐标关系查看工具
1、安装
sudo apt install ros-noetic-tf2-tools
2、启动
rosrun tf2_tools view_frames.py
二、rosbag包
一、作用
实现将程序的进程保存起来,事后还可以在重播
二、实现步骤
1.建立一个文件夹
2.在文件夹中建立××.bag文件用来保存录制信息
3.开始录制
rosbag record -a -o /home/zhangpeng/catkin_wstest/src/文件名.bag
4.查看文件
rosbag info /home/zhangpeng/catkin_wstest/src/bag/test_2021-08-26-17-00-25.bag
5.重播
rosbag play /home/zhangpeng/catkin_wstest/src/bag/test_2021-08-26-17-00-25.bag