发布里程计传感器信息
一。ROS使用tf来决定机器人的位置和静态地图中的传感器数据,但是tf中没有机 器人的速度信息,所以导航功能包要求机器人 能够通过里程计信息源发布包含速度信息的里程计nav_msgs/Odometry 消息。 本篇将介绍nav_msgs/Odometry消息,并且通过代码实现消息的发布,以及tf树的变换。这里使用一个简单的例程,实现 nav_msgs/Odometry消息的发布和tf变换,通过伪造的数据,实现机器人圆周运动。
ros工作空间中新建功能包,包含以下库
catkin_create_pkg odom_tf_package std_msgs rospy roscpp sensor_msgs tf nav_msgs
新建odom_tf_package/src/odom_tf_node.cpp
gedit odom_tf_node.cpp
粘贴进去:
复制代码#include <tf/transform_broadcaster.h>
#include <nav_msgs/Odometry.h>int main(int argc, char** argv)
{ros::init(argc, argv, "odometry_publisher");ros::NodeHandle n;ros::Publisher odom_pub = n.advertise<nav_msgs::Odometry>("odom", 50);tf::TransformBroadcaster odom_broadcaster;double x = 0.0;double y = 0.0;double th = 0.0;double vx = 0.1;double vy = -0.1;double vth = 0.1;ros::Time current_time, last_time;current_time = ros::Time::now();last_time = ros::Time::now();ros::Rate r(1.0);while(n.ok()){ros::spinOnce(); // check for incoming messagescurrent_time = ros::Time::now();//compute odometry in a typical way given the velocities of the robotdouble dt = (current_time - last_time).toSec();double delta_x = (vx * cos(th) - vy * sin(th)) * dt;double delta_y = (vx * sin(th) + vy * cos(th)) * dt;double delta_th = vth * dt;x += delta_x;y += delta_y;th += delta_th;//since all odometry is 6DOF we'll need a quaternion created from yawgeometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th);//first, we'll publish the transform over tfgeometry_msgs::TransformStamped odom_trans;odom_trans.header.stamp = current_time;odom_trans.header.frame_id = "odom";odom_trans.child_frame_id = "base_link";odom_trans.transform.translation.x = x;odom_trans.transform.translation.y = y;odom_trans.transform.translation.z = 0.0;odom_trans.transform.rotation = odom_quat;//send the transformodom_broadcaster.sendTransform(odom_trans);//next, we'll publish the odometry message over ROSnav_msgs::Odometry odom;odom.header.stamp = current_time;odom.header.frame_id = "odom";//set the positionodom.pose.pose.position.x = x;odom.pose.pose.position.y = y;odom.pose.pose.position.z = 0.0;odom.pose.pose.orientation = odom_quat;//set the velocityodom.child_frame_id = "base_link";odom.twist.twist.linear.x = vx;odom.twist.twist.linear.y = vy;odom.twist.twist.angular.z = vth;//publish the messageodom_pub.publish(odom);last_time = current_time;r.sleep();}
}
下面来剖析代码进行分析:
#include <tf/transform_broadcaster.h>#include <nav_msgs/Odometry.h>
我们需要实现“odom”参考系到“base_link”参考系的变换,以及nav_msgs/Odometry消息的发布,所以首先需要包含相关的头文件。
ros::Publisher odom_pub = n.advertise<nav_msgs::Odometry>("odom", 50); tf::TransformBroadcaster odom_broadcaster;
定义一个消息发布者来发布“odom”消息,在定义一个tf广播,来发布tf变换信息。
double x = 0.0;double y = 0.0; double th = 0.0;
默认机器人的起始位置是odom参考系下的0点。
double vx = 0.1;double vy = -0.1; double vth = 0.1;
我们设置机器人的默认前进速度,让机器人的base_link参考系在odom参考系下以x轴方向0.1m/s,Y轴速度-0.1m/s,角速度0.1rad/s的状态移动,这种状态下,可以让机器人保持圆周运动。
ros::Rate r(1.0);
使用1Hz的频率发布odom消息,当然,在实际系统中,往往需要更快的速度进行发布。
![](/assets/blank.gif)
//compute odometry in a typical way given the velocities of the robotdouble dt = (current_time - last_time).toSec();double delta_x = (vx * cos(th) - vy * sin(th)) * dt; double delta_y = (vx * sin(th) + vy * cos(th)) * dt; double delta_th = vth * dt; x += delta_x; y += delta_y; th += delta_th;
![](/assets/blank.gif)
使用我们设置的速度信息,来计算并更新里程计的信息,包括单位时间内机器人在x轴、y轴的坐标变化和角度的变化。在实际系统中,需要更具里程计的实际信息进行更新。
//since all odometry is 6DOF we'll need a quaternion created from yawgeometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th);
为了兼容二维和三维的功能包,让消息结构更加通用,里程计的偏航角需要转换成四元数才能发布,辛运的是,ROS为我们提供了偏航角与四元数相互转换的功能。
//first, we'll publish the transform over tfgeometry_msgs::TransformStamped odom_trans;odom_trans.header.stamp = current_time;odom_trans.header.frame_id = "odom"; odom_trans.child_frame_id = "base_link";
创建一个tf发布需要使用的TransformStamped类型消息,然后根据消息结构填充当前的时间戳、参考系id、子参考系id,注意两个参考系的id必须要是“odom”和“base_link”。
odom_trans.transform.translation.x = x;odom_trans.transform.translation.y = y;odom_trans.transform.translation.z = 0.0;odom_trans.transform.rotation = odom_quat;
填充里程计信息,然后发布tf变换的消息。
//next, we'll publish the odometry message over ROSnav_msgs::Odometry odom;odom.header.stamp = current_time;
我们还要发布nav_msgs/Odometry消息,让导航包获取机器人的速度。创建消息变量,然后填充时间戳。
![](/assets/blank.gif)
//set the positionodom.pose.pose.position.x = x;odom.pose.pose.position.y = y;odom.pose.pose.position.z = 0.0; odom.pose.pose.orientation = odom_quat; //set the velocity odom.child_frame_id = "base_link"; odom.twist.twist.linear.x = vx; odom.twist.twist.linear.y = vy; odom.twist.twist.angular.z = vth;
![](/assets/blank.gif)
填充机器人的位置、速度,然后发布消息。注意,我们发布的是机器人本体的信息,所以参考系需要填"base_link"。
1.3.编译源码:在odom_tf_package/CMakeLists.txt添加编译选项:
add_executable(odom_tf_node src/odom_tf_node.cpp)target_link_libraries(odom_tf_node ${catkin_LIBRARIES})
返回到你的工作空间的顶层目录下:
catkin_make
二。 在导航过程中,传感器的信息至关重要,这些传感器可以是激光雷达、摄像机、声纳、红外线、碰撞开关,但是归根结底,导航功能包要求机器人必须发布 sensor_msgs/LaserScan或sensor_msgs/PointCloud格式的传感器信息,本篇将详细介绍如何使用代码发布所需要的 消息。无论是 sensor_msgs/LaserScan,还是sensor_msgs/PointCloud ,都和ROS中tf帧信息等时间相关的消息一样,带标准格式的头信息。
![](/assets/blank.gif)
#Standard metadata for higher-level flow data types#sequence ID: consecutively increasing ID uint32 seq #Two-integer timestamp that is expressed as:# * stamp.secs: seconds (stamp_secs) since epoch # * stamp.nsecs: nanoseconds since stamp_secs # time-handling sugar is provided by the client library time stamp #Frame this data is associated with # 0: no frame # 1: global frame string frame_id
![](/assets/blank.gif)
以上是标准头信息的主要部分。seq是消息的顺序标识,不需要手动设置,发布节点在发布消息时,会自动累加。stamp 是消息中与数据相关联的时间戳, 例如激光数据中,时间戳对应激光数据的采集时间点。frame_id 是消息中与数据相关联的参考系id,例如在在激光数据中,frame_id对应激光 数据采集的参考系。
2.1.如何发布点云数据。
点云消息的结构
#This message holds a collection of 3d points, plus optional additional information about each point. #Each Point32 should be interpreted as a 3d point in the frame given in the header Header header geometry_msgs/Point32[] points #Array of 3d points ChannelFloat32[] channels #Each channel should have the same number of elements as points array, and the data in each channel should correspond 1:1 with each point
如上所示,点云消息的结构支持存储三维环境的点阵列,而且channels参数中,可以设置这些点云相关的数据,例如可以设置一个强度通道,存储每个点的数据强度,还可以设置一个系数通道,存储每个点的反射系数,等等。
2.2.通过代码发布点云数据
.在odom_tf_package/src下创建TF变换的代码文件:
gedit point_kinect_node.cpp
源代码如下:
![](/assets/blank.gif)
#include "ros/ros.h" #include <sensor_msgs/PointCloud.h>int main(int argc, char** argv) { ros::init(argc, argv, "point_cloud_publisher"); ros::NodeHandle n; ros::Publisher cloud_pub = n.advertise<sensor_msgs::PointCloud>("cloud", 50); unsigned int num_points = 100; int count = 0; ros::Rate r(1.0); while(n.ok()) { sensor_msgs::PointCloud cloud; cloud.header.stamp = ros::Time::now(); cloud.header.frame_id = "sensor_frame"; cloud.points.resize(num_points); //we'll also add an intensity channel to the cloud cloud.channels.resize(1); cloud.channels[0].name = "intensities"; cloud.channels[0].values.resize(num_points); //generate some fake data for our point cloud for(unsigned int i = 0; i < num_points; ++i) { cloud.points[i].x = 1 + count; cloud.points[i].y = 2 + count; cloud.points[i].z = 3 + count; cloud.channels[0].values[i] = 100 + count; } cloud_pub.publish(cloud); ++count; r.sleep(); } }
![](/assets/blank.gif)
分解代码来分析:
#include <sensor_msgs/PointCloud.h>
首先也是要包含sensor_msgs/PointCloud消息结构。
ros::Publisher cloud_pub = n.advertise<sensor_msgs::PointCloud>("cloud", 50);
定义一个发布点云消息的发布者。
sensor_msgs::PointCloud cloud;cloud.header.stamp = ros::Time::now();cloud.header.frame_id = "sensor_frame";
为点云消息填充头信息,包括时间戳和相关的参考系id。
cloud.points.resize(num_points);
设置存储点云数据的空间大小。
//we'll also add an intensity channel to the cloudcloud.channels.resize(1);cloud.channels[0].name = "intensities"; cloud.channels[0].values.resize(num_points);
设置一个名为“intensity“的强度通道,并且设置存储每个点强度信息的空间大小。
//generate some fake data for our point cloudfor(unsigned int i = 0; i < num_points; ++i){ cloud.points[i].x = 1 + count; cloud.points[i].y = 2 + count; cloud.points[i].z = 3 + count; cloud.channels[0].values[i] = 100 + count;
将我们伪造的数据填充到点云消息结构当中。
cloud_pub.publish(cloud);
最后,发布点云数据。
2.3.编译源码:在odom_tf_package/CMakeLists.txt添加编译选项:
add_executable(point_kinect_node src/point_kinect_node.cpp)target_link_libraries(point_kinect_node ${catkin_LIBRARIES})
返回到你的工作空间的顶层目录下:
catkin_make
三:测试代码:
roscorerosrun odom_tf_package odom_tf_noderosrun odom_tf_package point_kinect_node rviz
3.2.查看发布的点云数据。
rostopic echo /cloud
转载于:https://www.cnblogs.com/CZM-/p/5881685.html
发布里程计传感器信息相关推荐
- 【cartographer_ros】四: 发布和订阅里程计odom信息
上一节介绍了激光雷达Scan传感数据的订阅和发布. 本节会介绍里程计Odom数据的发布和订阅.里程计在cartographer中主要用于前端位置预估和后端优化. 官方文档: http://wiki.r ...
- ros(25):发布一个静态的里程计odom信息
有时为了验证程序可以运行,需要给程序输入一个里程计信息:有时为了在实车实验前验证程序,需要修改不同的里程计数据(可以在下面代码中增加一个odom_tmp的数组,或者用循环来使odom_tmp值变化), ...
- 移动机器人——里程计矫正
一.问题分析 机器人可以基于码盘数据和底盘运动学模型进行航迹推演,得到机器人的轨迹,但实际轨迹与推演轨迹存在误差,分析原因如下: 底盘实际尺寸与理论模型存在偏差,如轮子半径,两轮间距等: 底盘在运动过 ...
- 移动机器人轮式里程计
移动机器人灵魂三问:我在哪? 我要去哪里? 怎么去?其中,第一问对应机器人定位问题.定位问题可阐述为:移动机器人根据自身状态.传感器信息实时确定自己在世界(全局或局部)中的位置与姿态. 阿克曼转向的无 ...
- 3D激光SLAM:LeGO-LOAM---两步优化的帧间里程计及代码分析
3D激光SLAM:LeGO-LOAM---两步优化的帧间里程计及代码分析 前言 利用地面点优化 利用角点优化 代码部分 gazebo测试 前言 LeGO-LOAM的全称是 Lightweight an ...
- 【cartographer without ros】四、里程计odom数据转换
上一节介绍了cartographer中的TimedPointCloudData数据相关转换. 本节将介绍里程计Odom数据转换为cartographer中的OdometryData数据.还有carto ...
- LVI-SAM:使用SAM的激光-视觉-惯导紧耦合里程计
转载自:https://mp.weixin.qq.com/s/MlN-0BD9rAdJwsVco7TRlg LVI-SAM:使用SAM的激光-视觉-惯导紧耦合里程计 原创 泡泡机器人 泡泡机器人SLA ...
- 激光SLAM源码解析S-LOAM(三)里程计图优化
里程计,是通过累计帧间位姿变换得来的,因此会累积帧间误差. 如果想要纠正此累积误差,我们需要通过另一种方法得到可信位姿,以此校正相同时刻里程计位姿. SLAM图优化,是一种记录各帧时刻里程计,并通过可 ...
- 轮式里程计与激光雷达进行标定2--里程计运动学模型方法(理论+实现代码)
轮式里程计与激光雷达进行标定2--里程计运动学模型方法(理论+实现代码) 轮式里程计定义 轮式里程计与激光SLAM的关系 轮式里程计标定前言 轮式里程计与激光雷达标定数学建模 Code Result ...
最新文章
- VMware出现“该虚拟机似乎正在使用中 请获取所有权”
- python实现反转链表讲解_基于Python实现2种反转链表方法代码实例
- 5 个被忽视的习惯,决定了你很难成为高级开发工程师!
- Scala数组的mkString()方法
- 实践:使用FLANN.LSH进行检索
- matlab数组存字符串,MATLAB字符串数组存储为CSV格式
- [转载] python学习笔记
- unity3d collider自动调整大小_3dmax室内模型导入Unity3d快速烘焙光照【2020】
- 多线程的那点儿事(基础篇)
- 支付宝开放新玩法:搜商家可领消费券
- mysql通信协议的半双工机制理解
- linux夸分区软连接的作用,Linux 硬连接和软连接的原理 (in使用)
- 如何传输本地文件到服务器,本地传输文件到服务器
- Hackintosh_guide黑苹果
- wireshark提示未启动npf服务The NPF driver isn’t running You may have trouble capturing or listing interfaces
- 首届“中新人工智能高峰论坛”即将召开,周志华、李德毅......与你一起对话未来!...
- 今年这情况。。咱还是留个心眼吧
- md5加密以及可逆的加密解密算法
- differential privacy 学习笔记(一)
- 学习R语言编程——常用算法——导数与微积分的近似计算