cartographer 第三讲

第三讲 【cartographer】 添加功能以从RVIZ为纯本地化模式设置初始姿势

第一讲【ROS-SLAM】2D激光雷达 cartographer构建地图

第二讲 【cartographer】Ubuntu16.04 kinetic 最新版cartographer安装(2020/11/4更新)

第三讲 【cartographer】 添加功能以从RVIZ为纯本地化模式设置初始姿势

第四讲 【cartographer】纯定位 纯本地化 pure_localization

第五讲【cartographer】在仿真环境中 建图 纯定位

第六讲【cartographer】纯定位参数优化(初级篇)


文章目录


前言

cartographer作为一个谷歌开源的项目,在SLAM建图上拥有较好的性能,既然有建图的功能,也会有定位的功能,下面是讲述cartographer纯定位模式下的,添加功能以从RVIZ为纯本地化模式设置初始姿势。

一、RVIZ为纯本地化模式设置初始姿势

如果将cartographer作为一个定位算法使用,那么在RVIZ为纯本地化模式设置初始姿势必不可少。相比amcl,cartographer的很多功能并不完善,需要自己寻找代价添加功能。

顺便说一句,对于一个新入门的程序员来说,cartographer的纯本地化模式是比较难以掌握的,需要我们一步步解决各种问题。

二、使用步骤

1.引入库

1)cartographer_ros / CMakeLists.txt

添加

tf2_geometry_msgs

 
 
  • 1

2)cartographer_ros/cartographer_ros/CMakeLists.txt

添加

google_binary(set_initpose_from_rviz
  SRCS
  set_initpose_main.cc
)

install(TARGETS set_initpose_from_rviz
ARCHIVE DESTINATION ${ CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${ CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${ CATKIN_PACKAGE_BIN_DESTINATION}
)

3)cartographer_ros/launch/demo_backpack_2d_localization.launch

启动文件

  <node name="set_initpose" pkg="cartographer_ros" type="set_initpose_from_rviz" output="screen"
        args="
              -configuration_directory $(find cartographer_ros)/configuration_files
              -configuration_basename backpack_2d_localization.lua
              -load_state_filename $(arg load_state_filename)" >
  </node>

4)cartographer_ros/package.xml

添加

  <depend>tf2_geometry_msgs</depend>

2.添加功能代码

代码如下:
cartographer_ros/cartographer_ros/set_initpose_main.cc

/*
 * Copyright 2019 The Cartographer Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string>
#include <vector>

#include “cartographer/common/configuration_file_resolver.h”
#include “cartographer/io/proto_stream.h”
#include “cartographer/mapping/map_builder.h”
#include “cartographer_ros/node_constants.h”
#include “cartographer_ros/node_options.h”
#include “cartographer_ros/ros_log_sink.h”
#include “cartographer_ros_msgs/FinishTrajectory.h”
#include “cartographer_ros_msgs/GetTrajectoryStates.h”
#include “cartographer_ros_msgs/StartTrajectory.h”
#include “cartographer_ros_msgs/StatusCode.h”
#include “geometry_msgs/PoseWithCovarianceStamped.h”
#include “gflags/gflags.h”
#include “ros/ros.h”
#include “std_msgs/String.h”
#include “tf2_geometry_msgs/tf2_geometry_msgs.h”

DEFINE_string(configuration_directory, “”,
"First directory in which configuration files are searched, "
"second is always the Cartographer installation to allow "
“including files from there.”);
DEFINE_string(configuration_basename, “”,
"Basename, i.e. not containing any directory prefix, of the "
“configuration file.”);

DEFINE_string(load_state_filename, “”,
“Filename of a pbstream to draw a map from.”);

namespace {
std::unique_ptr<cartographer::mapping::MapBuilder> map_builder_;
} // namespace

// subscribe callback function from Rviz
void move_base_simple_callback(
const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& msg) {
::ros::NodeHandle nh;

// find the active active trajectory
::ros::ServiceClient client_get_trajectroy_states =
nh.serviceClient<cartographer_ros_msgs::GetTrajectoryStates>(
cartographer_ros::kGetTrajectoryStatesServiceName);

cartographer_ros_msgs::GetTrajectoryStates srv_get_trajectroy_states;
if (!client_get_trajectroy_states.call(srv_get_trajectroy_states)) {
LOG(ERROR) << "Failed to call "
<< cartographer_ros::kGetTrajectoryStatesServiceName << “.”;
}
if (srv_get_trajectroy_states.response.status.code !=
cartographer_ros_msgs::StatusCode::OK) {
LOG(ERROR) << “Error get trajectory states - message: '”
<< srv_get_trajectroy_states.response.status.message
<< "’ (status code: "
<< std::to_string(srv_get_trajectroy_states.response.status.code)
<< “).”;
return;
}

int current_trajectory_id = -1;
for (size_t i = 0; i < srv_get_trajectroy_states.response.trajectory_states
.trajectory_state.size();
i++) {
if (srv_get_trajectroy_states.response.trajectory_states.trajectory_state
.at(i) == cartographer_ros_msgs::TrajectoryStates::ACTIVE)
current_trajectory_id =
srv_get_trajectroy_states.response.trajectory_states.trajectory_id.at(
i);
}

if (current_trajectory_id == -1) {
LOG(ERROR) << “No active trajectory!”;
return;
}

// stop the current active trajectory
::ros::ServiceClient client_finish_trajectroy =
nh.serviceClient<cartographer_ros_msgs::FinishTrajectory>(
cartographer_ros::kFinishTrajectoryServiceName);
cartographer_ros_msgs::FinishTrajectory srv_finish_trajectroy;
srv_finish_trajectroy.request.trajectory_id = current_trajectory_id++;

if (!client_finish_trajectroy.call(srv_finish_trajectroy)) {
LOG(ERROR) << "Failed to call "
<< cartographer_ros::kFinishTrajectoryServiceName << “.”;
}
if (srv_finish_trajectroy.response.status.code !=
cartographer_ros_msgs::StatusCode::OK) {
LOG(ERROR) << “Error finishing trajectory - message: '”
<< srv_finish_trajectroy.response.status.message
<< "’ (status code: "
<< std::to_string(srv_finish_trajectroy.response.status.code)
<< “).”;
return;
}

// start a new trajectory
const auto node_poses = map_builder_->pose_graph()->GetTrajectoryNodePoses();

// get the start pose of the trajectory0 w.r.t /map
const auto traj_ref_pose = node_poses.BeginOfTrajectory(0)->data.global_pose;
tf2::Transform traj_ref_tf;
traj_ref_tf.getOrigin() = tf2::Vector3(traj_ref_pose.translation().x(),
traj_ref_pose.translation().y(),
traj_ref_pose.translation().z());
traj_ref_tf.setRotation(tf2::Quaternion(
traj_ref_pose.rotation().x(), traj_ref_pose.rotation().y(),
traj_ref_pose.rotation().z(), traj_ref_pose.rotation().w()));

// get init pose w.r.t /map
tf2::Transform map_tf;
tf2::fromMsg(msg->pose.pose, map_tf);
tf2::Transform relative_initpose_tf = traj_ref_tf.inverse() * map_tf;

// set the start trajectory service call
::ros::ServiceClient client_start_trajectroy =
nh.serviceClient<cartographer_ros_msgs::StartTrajectory>(
cartographer_ros::kStartTrajectoryServiceName);
cartographer_ros_msgs::StartTrajectory srv_start_trajectroy;
srv_start_trajectroy.request.configuration_directory =
FLAGS_configuration_directory;
srv_start_trajectroy.request.configuration_basename =
FLAGS_configuration_basename;

srv_start_trajectroy.request.relative_to_trajectory_id =
0; // frozen trajectory
srv_start_trajectroy.request.use_initial_pose = true;
tf2::toMsg(relative_initpose_tf, srv_start_trajectroy.request.initial_pose);

if (!client_start_trajectroy.call(srv_start_trajectroy)) {
LOG(ERROR) << "Failed to call "
<< cartographer_ros::kStartTrajectoryServiceName << “.”;
}
if (srv_start_trajectroy.response.status.code !=
cartographer_ros_msgs::StatusCode::OK) {
LOG(ERROR) << “Error starting trajectory - message: '”
<< srv_start_trajectroy.response.status.message
<< "’ (status code: "
<< std::to_string(srv_start_trajectroy.response.status.code)
<< “).”;
}
}

int main(int argc, char argv) {
google::InitGoogleLogging(argv[0]);

google::SetUsageMessage(
“\n\n”
"Convenience tool around the start_trajectory service. This takes a Lua "
"file that is accepted by the node as well and starts a new trajectory "
“using its settings.\n”);

google::ParseCommandLineFlags(&argc, &argv, true);

CHECK(!FLAGS_configuration_basename.empty())
<< “-configuration_basename is missing.”;

CHECK(!FLAGS_configuration_directory.empty())
<< “-configuration_directory is missing.”;

// load pbstream
::cartographer::io::ProtoStreamReader reader(FLAGS_load_state_filename);
cartographer_ros::NodeOptions node_options;
std::tie(node_options, std::ignore) = cartographer_ros::LoadOptions(
FLAGS_configuration_directory, FLAGS_configuration_basename);
map_builder_ = absl::make_unique<cartographer::mapping::MapBuilder>(
node_options.map_builder_options);
map_builder_->LoadState(&reader, true);

::ros::init(argc, argv, “cartographer_start_trajectory”);
::ros::start();

::ros::NodeHandle nh;
::ros::Subscriber sub_move_base_simple =
nh.subscribe<geometry_msgs::PoseWithCovarianceStamped>(
“/initialpose”, 1, &move_base_simple_callback);
::ros::spin();
}


总结

以上就是今天要讲的内容,本文介绍了cartographer纯本地化模式下如何设置初始姿势的功能。

参考链接:https://github.com/cartographer-project/cartographer_ros/pull/1284/files

上一篇:我的ROS学习之路——多坐标变换


下一篇:发布者publisher的编程实现