【cartographer_ros】四: 发布和订阅里程计odom信息
阅读原文时间:2022年07月08日阅读:2

上一节介绍了激光雷达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){
&nbsp; ros::init(argc, argv, "odometry_publisher");

&nbsp; //创建一个ros::Publisher和一个tf::TransformBroadcaster以便能够分别使用 ROS 和 tf 发送消息。
&nbsp; ros::NodeHandle n;
&nbsp; ros::Publisher odom_pub = n.advertise<nav_msgs::Odometry>("odom", 50);
&nbsp; tf::TransformBroadcaster odom_broadcaster;

&nbsp; double x = 0.0;
&nbsp; double y = 0.0;
&nbsp; double th = 0.0;

&nbsp; double vx = 0.1;
&nbsp; double vy = -0.1;
&nbsp; double vth = 0.1;

&nbsp; ros::Time current_time, last_time;
&nbsp; current_time = ros::Time::now();
&nbsp; last_time = ros::Time::now();

&nbsp; ros::Rate r(1.0);
&nbsp; while(n.ok()){

&nbsp; &nbsp; ros::spinOnce(); &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;
&nbsp; &nbsp; current_time = ros::Time::now();

&nbsp; &nbsp; //根据设置的速度更新里程信息
&nbsp; &nbsp; double dt = (current_time - last_time).toSec();
&nbsp; &nbsp; double delta_x = (vx * cos(th) - vy * sin(th)) * dt;
&nbsp; &nbsp; double delta_y = (vx * sin(th) + vy * cos(th)) * dt;
&nbsp; &nbsp; double delta_th = vth * dt;

&nbsp; &nbsp; x += delta_x;
&nbsp; &nbsp; y += delta_y;
&nbsp; &nbsp; th += delta_th;

&nbsp; &nbsp; geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(th);

&nbsp; &nbsp; //创建一个TransformStamped消息,通过 tf发布从“odom”到“base_link”的转换
&nbsp; &nbsp; geometry_msgs::TransformStamped odom_trans;
&nbsp; &nbsp; odom_trans.header.stamp = current_time;
&nbsp; &nbsp; odom_trans.header.frame_id = "odom";
&nbsp; &nbsp; odom_trans.child_frame_id = "base_link";

&nbsp; &nbsp; odom_trans.transform.translation.x = x;
&nbsp; &nbsp; odom_trans.transform.translation.y = y;
&nbsp; &nbsp; odom_trans.transform.translation.z = 0.0;
&nbsp; &nbsp; odom_trans.transform.rotation = odom_quat;

&nbsp; &nbsp; odom_broadcaster.sendTransform(odom_trans);

&nbsp; &nbsp; //填充Odometry消息
&nbsp; &nbsp; nav_msgs::Odometry odom;
&nbsp; &nbsp; odom.header.stamp = current_time;
&nbsp; &nbsp; odom.header.frame_id = "odom";

&nbsp; &nbsp; //设置位置
&nbsp; &nbsp; odom.pose.pose.position.x = x;
&nbsp; &nbsp; odom.pose.pose.position.y = y;
&nbsp; &nbsp; odom.pose.pose.position.z = 0.0;
&nbsp; &nbsp; odom.pose.pose.orientation = odom_quat;

&nbsp; &nbsp; //设置速度
&nbsp; &nbsp; odom.child_frame_id = "base_link";
&nbsp; &nbsp; odom.twist.twist.linear.x = vx;
&nbsp; &nbsp; odom.twist.twist.linear.y = vy;
&nbsp; &nbsp; odom.twist.twist.angular.z = vth;

&nbsp; &nbsp; //发布Odometry消息
&nbsp; &nbsp; odom_pub.publish(odom);

&nbsp; &nbsp; last_time = current_time;
&nbsp; &nbsp; r.sleep();
&nbsp; }
}

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)
{

&nbsp; &nbsp; double x, y, z;
&nbsp; &nbsp; double roll, pitch, yaw;
&nbsp; &nbsp; x = msg->pose.pose.position.x;
&nbsp; &nbsp; y = msg->pose.pose.position.y;
&nbsp; &nbsp; z = msg->pose.pose.position.z;
&nbsp; &nbsp; tf::Quaternion quat; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; //定义一个四元数
&nbsp; &nbsp; tf::quaternionMsgToTF(msg->pose.pose.orientation, quat); //取出方向存储于四元数
&nbsp; &nbsp; tf::Matrix3x3(quat).getRPY(roll, pitch, yaw);

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

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

【完】


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