Cartographer_ros主要實現Topics的訂閱與發布。訂閱是指從IMU,激光雷達,里程計取數據,然后傳給Cartographer庫。發布是指從Cartographer拿處理的結果,然后發布給ROS,然后可以在rivz上顯示。
1. cartographer_ros/docs/source/ros_api.rst
此文件描述 了Cartographer_ros訂閱與發布了哪些topics及服務。
2.運行 cartographer_ros
roslaunch cartographer_ros demo_revo_lds.launch
3.revo_lds.lua
此配置文件,描述了發布哪些Topics及名稱。在源碼中。訂閱的Topic在源碼中通過ratio of the pulse(脈沖的比率)的方式來定時調用。發布是通過定時器的方式,定時發布。具體值,可以通過此配置文件配置。
1)定時器方式
wall_timers_.push_back(node_handle_.createWallTimer(
::ros::WallDuration(node_options_.submap_publish_period_sec),
&Node::PublishSubmapList, this));
2)ratio方式
void Node::HandlePointCloud2Message(
const int trajectory_id, const std::string& sensor_id,
const sensor_msgs::PointCloud2::ConstPtr& msg) {
absl::MutexLock lock(&mutex_);
if (!sensor_samplers_.at(trajectory_id).rangefinder_sampler.Pulse()) {
return;
}
map_builder_bridge_.sensor_bridge(trajectory_id)
->HandlePointCloud2Message(sensor_id, msg);
}
4. cartographer_node
Cartographer_ros中的一個重要節點
1.請先查看:cartographer_ros/docs/source/ros_api.rst 文檔
====================
Subscribed Topics:
scan (`sensor_msgs/LaserScan`_)
echoes (`sensor_msgs/MultiEchoLaserScan`_)
points2 (`sensor_msgs/PointCloud2`_)
imu (`sensor_msgs/Imu`_)
odom (`nav_msgs/Odometry`_)
Published Topics:
submap_list (`cartographer_ros_msgs/SubmapList`_)
Services:
submap_query (`cartographer_ros_msgs/SubmapQuery`_)
start_trajectory (`cartographer_ros_msgs/StartTrajectory`_)
trajectory_query (`cartographer_ros_msgs/TrajectoryQuery`_)
finish_trajectory (`cartographer_ros_msgs/FinishTrajectory`_)
write_state (`cartographer_ros_msgs/WriteState`_)
get_trajectory_states (`cartographer_ros_msgs/GetTrajectoryStates`_)
read_metrics (`cartographer_ros_msgs/ReadMetrics`_)
====================
2. 運行cartographer_ros
roslaunch cartographer_ros demo_revo_lds.launch
================================
3.revo_lds.lua
demo_revo_lds.launch 指定加載revo_lds.lua 配置文件。指定topic的名稱,發布的Topic的時間間隔。
map_frame = "map",
tracking_frame = "scan",
published_frame = "scan",
odom_frame = "odom",
provide_odom_frame = false,
use_odometry = false,
use_nav_sat = false,
use_landmarks = false,
publish_frame_projected_to_2d=false,
num_laser_scans = 1,
num_multi_echo_laser_scans = 0,
num_subdivisions_per_laser_scan = 1,
num_point_clouds = 0,
lookup_transform_timeout_sec = 0.2,
submap_publish_period_sec = 0.3,
pose_publish_period_sec = 5e-3,
trajectory_publish_period_sec = 30e-3,
rangefinder_sampling_ratio = 1.,
odometry_sampling_ratio = 1.,
fixed_frame_pose_sampling_ratio = 1.,
imu_sampling_ratio = 1.,
landmarks_sampling_ratio = 1.,
===========
map_frame:一般為“map”.用來發布submap的ROS幀ID.
tracking_frame:SLAM算法要跟蹤的ROS 幀ID.?
published_frame:用來發布pose的幀ID.?
odom_frame:只要當有里程計信息的時候才會使用。即provide_odom_frame=true.
provide_odom_frame:如果為true,the local, non-loop-closed, continuous pose將會在map_frame 里以odom_frame發布?
publish_frame_projected_to_2d:如果為true,則已經發布的pose將會被完全成2D的pose,沒有 roll,pitch或者z-offset?
use_odometry:如果為true,需要提供里程計信息,並話題/odom會訂閱nav_msgs/Odometry類型的消 息,在SLAM過程中也會使用這個消息進行建圖
use_nav_sat:如果為true,會在話題/fix上訂閱sensor_msgs/NavSatFix類型的消息,並且在 globalSLAM中會用到
use_landmarks:如果為true,會在話題/landmarks上訂閱cartographer_ros_msgs/LandmarkList類型 的消息,並且在SLAM過程中會用到
num_laser_scans:SLAM可以輸入的/scan話題數目的最大值
num_muti_echo_laser_scans:SLAM可以輸入sensor_msgs/MultiEchoLaserScan話題數目的最大值
num_subdivisions_per_laser_scan:將每個接收到的(multi_echo)激光scan分割成的點雲數。 細分 scam可以在掃描儀移動時取消scanner獲取的scan。 有一個相應的trajectory builder option可將細分掃描累積到將用於scan_matching的點雲中。
num_point_clouds:SLAM可以輸入的sensor_msgs/PointCloud2話題數目的最大值
lookup_transform_timeout_sec:使用tf2查找transform的超時時間(秒)。
submap_publish_period_sec:發布submap的時間間隔(秒)
pose_publish_period_sec:發布pose的時間間隔,值為5e-3的時候為200HZ
trajectory_publish_period_sec:發布trajectory markers(trajectory的節點)的時間間隔,值為30e-3 為30ms
rangefinder_samping_ratio:測距儀的固定采樣ratio
imu_sampling_ratio:IMU message的固定采樣ratio
landmarks_sampling_ratio:landmarks message的固定采樣ratio,(單位是啥?)
=====================
4.RVIZ 訂閱的topic
1)TF
2)/submap_list
3)/scan_matched_points2
4)/trajectory_node_list
5)/landmark_poses_list
6)/constraint_list
5.App
cartographer_assets_writer
cartographer_dev_trajectory_comparison
cartographer_offline_node
cartographer_rosbag_validate
cartographer_dev_pbstream_trajectories_to_rosbag
cartographer_node
cartographer_pbstream_map_publisher
cartographer_dev_rosbag_publisher
cartographer_occupancy_grid_node
cartographer_pbstream_to_ros_map
6. Note.cpp 源碼分析
0.Node構造函數
1) 定義各種topic
submap_list_publisher_ =
node_handle_.advertise<::cartographer_ros_msgs::SubmapList>(
kSubmapListTopic, kLatestOnlyPublisherQueueSize);
trajectory_node_list_publisher_ =
node_handle_.advertise<::visualization_msgs::MarkerArray>(
kTrajectoryNodeListTopic, kLatestOnlyPublisherQueueSize);
landmark_poses_list_publisher_ =
node_handle_.advertise<::visualization_msgs::MarkerArray>(
kLandmarkPosesListTopic, kLatestOnlyPublisherQueueSize);
constraint_list_publisher_ =
node_handle_.advertise<::visualization_msgs::MarkerArray>(
kConstraintListTopic, kLatestOnlyPublisherQueueSize);
scan_matched_point_cloud_publisher_ =
node_handle_.advertise<sensor_msgs::PointCloud2>(
kScanMatchedPointCloudTopic, kLatestOnlyPublisherQueueSize);
2)定義各種服務的發布器。
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));
3)給各個發布器設置一個時鍾,綁定時間到了的處理函數
wall_timers_.push_back(node_handle_.createWallTimer(
::ros::WallDuration(node_options_.submap_publish_period_sec),
&Node::PublishSubmapList, this));
wall_timers_.push_back(node_handle_.createWallTimer(
::ros::WallDuration(node_options_.trajectory_publish_period_sec),
&Node::PublishTrajectoryNodeList, this));
……
1.Run
cartographer_ros/cartographer_ros/cartographer_ros/node_main.cc
1)創建一個map_builder
2)創建一個 node
3)node.StartTrajectoryWithDefaultTopics()->AddTrajectory()
2.AddTrajectory
cartographer_ros/cartographer_ros/cartographer_ros/node.cc
1)map_builder_bridge_.AddTrajectory
map_builder_->AddTrajectoryBuilder->OnLocalSlamResult
2)AddExtrapolator 插入一個Extrapolator 位姿解析器
3)AddSensorSamplers
插入一TrajectorySensorSamplers,里面有rangefinder_sampler,odometry_sampler
,fixed_frame_pose_sampler,imu_sampler,landmark_sampler
4)LaunchSubscribers:訂閱相關的topics,並指安處理函數
subscribers_[trajectory_id].push_back(
{SubscribeWithHandler<sensor_msgs::LaserScan>(
&Node::HandleLaserScanMessage, trajectory_id, topic, &node_handle_,
this),
topic});
subscribers_[trajectory_id].push_back(
{SubscribeWithHandler<sensor_msgs::MultiEchoLaserScan>(
&Node::HandleMultiEchoLaserScanMessage, trajectory_id, topic,
&node_handle_, this),
topic});
如果使用IMU的數據,則:
subscribers_[trajectory_id].push_back(
{SubscribeWithHandler<sensor_msgs::Imu>(&Node::HandleImuMessage,
trajectory_id, kImuTopic,
&node_handle_, this),
如果使用里程計的數據,則:
subscribers_[trajectory_id].push_back( {SubscribeWithHandler<nav_msgs::Odometry>
(&Node::HandleOdometryMessage, trajectory_id, kOdometryTopic,
&node_handle_, this),
如果使用導航,則
subscribers_[trajectory_id].push_back(
{SubscribeWithHandler<sensor_msgs::NavSatFix>(
&Node::HandleNavSatFixMessage, trajectory_id, kNavSatFixTopic,
&node_handle_, this)
如果使用landmaks,則:
subscribers_[trajectory_id].push_back(
{SubscribeWithHandler<cartographer_ros_msgs::LandmarkList>(
&Node::HandleLandmarkMessage, trajectory_id, kLandmarkTopic,
&node_handle_, this),
1./submap_list topic的數據
header:
seq: 272
stamp:
secs: 0
nsecs: 0
frame_id: "map"
submap:
-
trajectory_id: 0
submap_index: 0
submap_version: 50
pose:
position:
x: 0.0
y: 0.0
z: 0.0
orientation:
x: 0.0
y: 0.0
z: 0.0
w: 1.0
is_frozen: False
2. /constraint_list
header:
seq: 0
stamp:
secs: 0
nsecs: 0
frame_id: "map"
ns: "Inter constraints, different trajectories"
id: 4
type: 5
action: 0
pose:
position:
x: 0.0
y: 0.0
z: 0.1
orientation:
x: 0.0
y: 0.0
z: 0.0
w: 1.0
scale:
x: 0.025
y: 0.0
z: 0.0
color:
r: 0.0
g: 0.0
b: 0.0
a: 0.0
lifetime:
secs: 0
nsecs: 0
frame_locked: False
points: []
colors: []
text: ''
mesh_resource: ''
mesh_use_embedded_materials: False
3. /trajectory_node_list
header:
seq: 0
stamp:
secs: 0
nsecs: 0
frame_id: "map"
ns: "Trajectory 0"
id: 2
type: 4
action: 0
pose:
position:
x: 0.0
y: 0.0
z: 0.05
orientation:
x: 0.0
y: 0.0
z: 0.0
w: 1.0
scale:
x: 0.07
y: 0.0
z: 0.0
color:
r: 0.207129895687
g: 0.115499980748
b: 0.769999980927
a: 0.25
lifetime:
secs: 0
nsecs: 0
frame_locked: False
points:
-
x: 1.02211357213
y: 2.15808512043
z: 0.0
-
x: 1.05474171104
y: 2.13220375749
z: 0.0
-
x: 1.0466034346
y: 2.12491221525
z: 0.0
colors: []
text: ''
mesh_resource: ''
mesh_use_embedded_materials: False
4./tf
transforms:
-
header:
seq: 0
stamp:
secs: 1574159625
nsecs: 351509220
frame_id: "/base_footprint"
child_frame_id: "/laser_frame"
transform:
translation:
x: 0.2245
y: 0.0
z: 0.2
rotation:
x: 0.0
y: 0.0
z: 0.0
w: 1.0