服务介绍-Node类-cartographer
Kong Liangqian Lv6

在构造Node类的时候,cartographer也声明了一些服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Step: 2 声明发布对应名字的ROS服务, 并将服务的发布器放入到vector容器中
service_servers_.push_back(node_handle_.advertiseService(
kSubmapQueryServiceName, &Node::HandleSubmapQuery, this));
service_servers_.push_back(node_handle_.advertiseService(
kTrajectoryQueryServiceName, &Node::HandleTrajectoryQuery, this));
service_servers_.push_back(node_handle_.advertiseService(
kStartTrajectoryServiceName, &Node::HandleStartTrajectory, this));
service_servers_.push_back(node_handle_.advertiseService(
kFinishTrajectoryServiceName, &Node::HandleFinishTrajectory, this));
service_servers_.push_back(node_handle_.advertiseService(
kWriteStateServiceName, &Node::HandleWriteState, this));
service_servers_.push_back(node_handle_.advertiseService(
kGetTrajectoryStatesServiceName, &Node::HandleGetTrajectoryStates, this));
service_servers_.push_back(node_handle_.advertiseService(
kReadMetricsServiceName, &Node::HandleReadMetrics, this));

获取submap

服务内容包括,处理获取对应id轨迹的 索引为submap_index 的submap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @brief 获取对应id轨迹的 索引为submap_index 的submap
*
* @param[in] request 获取submap的请求
* @param[out] response 服务的回应
* @return true: ROS的service只能返回true, 返回false程序会中断
*/
bool Node::HandleSubmapQuery(
::cartographer_ros_msgs::SubmapQuery::Request& request,
::cartographer_ros_msgs::SubmapQuery::Response& response) {
absl::MutexLock lock(&mutex_);
map_builder_bridge_.HandleSubmapQuery(request, response);
return true;
}

消息的数据结构SubmapQuery,可以从cartographer_ros/srv里面查看

1
2
3
4
5
6
int32 trajectory_id
int32 submap_index
---
cartographer_ros_msgs/StatusResponse status
int32 submap_version
cartographer_ros_msgs/SubmapTexture[] textures

获取对应ID的轨迹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
* @brief 获取对应id的轨迹
*
* @param[in] request
* @param[out] response
* @return true: ROS的service只能返回true, 返回false程序会中断
*/
bool Node::HandleTrajectoryQuery(
::cartographer_ros_msgs::TrajectoryQuery::Request& request,
::cartographer_ros_msgs::TrajectoryQuery::Response& response) {
absl::MutexLock lock(&mutex_);

// 检查对应id的轨迹是否存在, 如果存在判断一下该id轨迹的状态
response.status = TrajectoryStateToStatus(
request.trajectory_id,
{TrajectoryState::ACTIVE, TrajectoryState::FINISHED,
TrajectoryState::FROZEN} /* valid states */);
if (response.status.code != cartographer_ros_msgs::StatusCode::OK) {
LOG(ERROR) << "Can't query trajectory from pose graph: "
<< response.status.message;
return true;
}
// 获取轨迹
map_builder_bridge_.HandleTrajectoryQuery(request, response);
return true;
}

开启一条新的轨迹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
* @brief 通过服务来开始一条新的轨迹
*
* @param[in] request
* 配置文件的目录与名字, 是否使用初始位姿, 初始位姿以及其是相对于哪条轨迹的id,
* @param[out] response 返回轨迹的状态与id
* @return true: ROS的service只能返回true, 返回false程序会中断
*/
bool Node::HandleStartTrajectory(
::cartographer_ros_msgs::StartTrajectory::Request& request,
::cartographer_ros_msgs::StartTrajectory::Response& response) {
TrajectoryOptions trajectory_options;
// 获取配置文件内容
std::tie(std::ignore, trajectory_options) = LoadOptions(
request.configuration_directory, request.configuration_basename);

// 如果给定了一个初始位姿
if (request.use_initial_pose) {
const auto pose = ToRigid3d(request.initial_pose);
if (!pose.IsValid()) {
response.status.message =
"Invalid pose argument. Orientation quaternion must be normalized.";
LOG(ERROR) << response.status.message;
response.status.code =
cartographer_ros_msgs::StatusCode::INVALID_ARGUMENT;
return true;
}

// Check if the requested trajectory for the relative initial pose exists.
// 检查 initial_pose 对应的轨迹id是否存在
response.status = TrajectoryStateToStatus(
request.relative_to_trajectory_id,
{TrajectoryState::ACTIVE, TrajectoryState::FROZEN,
TrajectoryState::FINISHED} /* valid states */);
if (response.status.code != cartographer_ros_msgs::StatusCode::OK) {
LOG(ERROR) << "Can't start a trajectory with initial pose: "
<< response.status.message;
return true;
}

::cartographer::mapping::proto::InitialTrajectoryPose
initial_trajectory_pose;
initial_trajectory_pose.set_to_trajectory_id(
request.relative_to_trajectory_id);
// 将pose转成proto格式,放进initial_trajectory_pose
*initial_trajectory_pose.mutable_relative_pose() =
cartographer::transform::ToProto(pose);
initial_trajectory_pose.set_timestamp(cartographer::common::ToUniversal(
::cartographer_ros::FromRos(ros::Time(0))));

// 将初始位姿信息加入到trajectory_options中
*trajectory_options.trajectory_builder_options
.mutable_initial_trajectory_pose() = initial_trajectory_pose;
}

// 检查TrajectoryOptions是否存在2d或者3d轨迹的配置信息
if (!ValidateTrajectoryOptions(trajectory_options)) {
response.status.message = "Invalid trajectory options.";
LOG(ERROR) << response.status.message;
response.status.code = cartographer_ros_msgs::StatusCode::INVALID_ARGUMENT;
}
// 检查topic名字是否被其他轨迹使用
else if (!ValidateTopicNames(trajectory_options)) {
response.status.message = "Topics are already used by another trajectory.";
LOG(ERROR) << response.status.message;
response.status.code = cartographer_ros_msgs::StatusCode::INVALID_ARGUMENT;
}
// 检查通过, 添加一个新的轨迹
else {
response.status.message = "Success.";
response.trajectory_id = AddTrajectory(trajectory_options);
response.status.code = cartographer_ros_msgs::StatusCode::OK;
}
return true;
}

// 使用默认topic名字开始一条轨迹,也就是开始slam
void Node::StartTrajectoryWithDefaultTopics(const TrajectoryOptions& options) {
absl::MutexLock lock(&mutex_);
// 检查TrajectoryOptions是否存在2d或者3d轨迹的配置信息
CHECK(ValidateTrajectoryOptions(options));
// 添加一条轨迹
AddTrajectory(options);
}

结束一条轨迹

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @brief 结束一条轨迹
*
* @param[in] request 轨迹的id
* @param[out]] response 返回StatusResponse格式的处理状态
* @return true
*/
bool Node::HandleFinishTrajectory(
::cartographer_ros_msgs::FinishTrajectory::Request& request,
::cartographer_ros_msgs::FinishTrajectory::Response& response) {
absl::MutexLock lock(&mutex_);
response.status = FinishTrajectoryUnderLock(request.trajectory_id);
return true;
}

获得所有轨迹的状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* @brief 获取所有轨迹的状态
*
* @param[in] request 无
* @param[out] response 返回所有轨迹的状态
* @return true
*/
bool Node::HandleGetTrajectoryStates(
::cartographer_ros_msgs::GetTrajectoryStates::Request& request,
::cartographer_ros_msgs::GetTrajectoryStates::Response& response) {
// enum class TrajectoryState { ACTIVE, FINISHED, FROZEN, DELETED };
using TrajectoryState =
::cartographer::mapping::PoseGraphInterface::TrajectoryState;

absl::MutexLock lock(&mutex_);
response.status.code = ::cartographer_ros_msgs::StatusCode::OK;
response.trajectory_states.header.stamp = ros::Time::now();
for (const auto& entry : map_builder_bridge_.GetTrajectoryStates()) {
// 轨迹的id
response.trajectory_states.trajectory_id.push_back(entry.first);
// 每个轨迹对应一个TrajectoryStates
switch (entry.second) {
case TrajectoryState::ACTIVE:
response.trajectory_states.trajectory_state.push_back(
::cartographer_ros_msgs::TrajectoryStates::ACTIVE);
break;
case TrajectoryState::FINISHED:
response.trajectory_states.trajectory_state.push_back(
::cartographer_ros_msgs::TrajectoryStates::FINISHED);
break;
case TrajectoryState::FROZEN:
response.trajectory_states.trajectory_state.push_back(
::cartographer_ros_msgs::TrajectoryStates::FROZEN);
break;
case TrajectoryState::DELETED:
response.trajectory_states.trajectory_state.push_back(
::cartographer_ros_msgs::TrajectoryStates::DELETED);
break;
}
}
return true;
}
 Comments