资讯详情

【cartographer_ros】四: 发布和订阅里程计odom信息

最后一节介绍了激光雷达Scan订阅和发布传感数据。

本节将介绍里程计Odom发布和订阅数据。cartographer主要用于前端位置预测和后端优化。

官方文档:http://wiki.ros.org/navigation/Tutorials/RobotSetup/Odom


1:nav_msgs/Odometry消息类型

2:发布Odometry消息

3:订阅Odometry消息


1:nav_msgs/Odometry消息类型

查看终端信息数据结构:

rosmsg show nav_msgs/Odometry

Odometry数据结构如下:

Header header string child_frame_id geometry_msgs/PoseWithCovariance pose geometry_msgs/TwistWithCovariance twist

其中pose是位置数据,twist是速度数据。 由于还有其他数据结构,这里展开一下,更加清晰:


2:发布Odometry消息

在一个圆圈中行驶的假机器人里程计数据被定义为发布

#include <ros/ros.h> #include <tf/transform_broadcaster.h> #include <nav_msgs/Odometry.h>  int main(int argc, char** argv){  ros::init(argc, argv, "odometry_publisher");   //创建一个ros::Publisher和一个tf::TransformBroadcaster可单独使用 ROS 和 tf 发送消息。  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();         current_time = ros::Time::now();    ///以设定的速度更新里程信息   double 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;    geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th);    //创建一个TransformStamped消息,通过 tf发布从“odom”到“base_link”的转换   geometry_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;    odom_broadcaster.sendTransform(odom_trans);    //填充Odometry消息   nav_msgs::Odometry odom;   odom.header.stamp = current_time;   odom.header.frame_id = "odom";    //设置位置   odom.pose.pose.position.x = x;   odom.pose.pose.position.y = y;   odom.pose.pose.position.z = 0.0;   odom.pose.pose.orientation = odom_quat;    //设置速度   odom.child_frame_id = "base_link";   odom.twist.twist.linear.x = vx;   odom.twist.twist.linear.y = vy;   odom.twist.twist.angular.z = vth;    //发布Odometry消息   odom_pub.publish(odom);    last_time = current_time;   r.sleep();  } }


3:订阅Odometry消息

(1) 通过rosbag订阅

rostopic echo /odom

(2) 通过rviz查看 打开rviz

rosrun rviz rviz

Fixed Frame修改为base_link,添加Odometry并将Topic设为/odom(3) 编程打印

#include "ros/ros.h" #include "nav_msgs/Odometry.h" #include "tf/transform_listener.h"  void OdomCallback(const nav_msgs::Odometry::ConstPtr &msg) {    double x, y, z;   double roll, pitch, yaw;   x = msg->pose.pose.position.x;   y = msg->pose.pose.position.y;   z = msg->pose.pose.position.z;   tf::Qaternion quat;                                     //定义一个四元数
    tf::quaternionMsgToTF(msg->pose.pose.orientation, quat); //取出方向存储于四元数
    tf::Matrix3x3(quat).getRPY(roll, pitch, yaw);

    ROS_INFO("Odom: %f, %f, %f, %f, %f, %f", x, y, z, roll, pitch, yaw);
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "listener");
    ros::NodeHandle node;
    ros::Subscriber subOdom = node.subscribe("odom", 1000, OdomCallback);
    ros::spin();
    return 0;
}


下一节会介绍陀螺仪Imu数据的发布和订阅

标签: 轮速传感器传感头

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台