Ros

nav_msgs::OccupancyGrid

Ros用OccupancyGrid存储栅格地图,栅格图表示了障碍物在真实地图上的分布情况。

C:\Windows\System32>rosmsg show nav_msgs/OccupancyGrid
std_msgs/Header header
  uint32 seq
  time stamp
  string frame_id
nav_msgs/MapMetaData info
  time map_load_time
  float32 resolution
  uint32 width
  uint32 height
  geometry_msgs/Pose origin
    geometry_msgs/Point position
      float64 x
      float64 y
      float64 z
    geometry_msgs/Quaternion orientation
      float64 x
      float64 y
      float64 z
      float64 w
int8[] data

nav_msgs::OccupancyGrid分为三个部分。以图1中比例尺(resolution)为0.05,栅格数为105x150,实际大小为5.249mx7.5m的地图举例说明。CreateOccupancyGridMsg代码则显示了是如何填充这些值。

图1 slam建图时的OccupancyGrid

第一部分:std_msgs/Header header

  • uint32 seq。帧序列号。图1中这个值是0。
  • time stamp。时间戳。
  • string frame_id。地图参考的坐标系。图1中是“map”。

第二部分:nav_msgs/MapMetaData info

  • time map_load_time。地图加载时间。图1中这值等于header.stamp。
  • float32 resolution。比例尺,代表一个栅格在实际地图中的尺寸。单位:米/栅格。在后绪显示栅格图像时,往往用一个像素表示一个栅格,于是有时也称每个像素表示多少米。
  • uint32 width。地图宽度,这里指的是栅格数量,不是指实际长度。图1是105。
  • uint32 height。地图高度。和宽度一样,这里指的是栅格数量,不是指实际长度。图1是150。
  • geometry_msgs/Pose origin。一般来说,geometry_msgs/Pose用于表示位姿,但这里不是该功能,只是恰好能借用它的两个字段。
  • geometry_msgs/Point position。原点在真实地图下的坐标,单位米,对2D slam,z固定0。所谓原点,对应真实世界中机器人中心在开始时刻落在的那个位置。设想这么个场景,机器人放在位置p,这时激光雷达开始扫描,立刻会在p周围形成一圈障碍物,见图1中红色表示的障碍物,并产生一个能包含所有障碍物的最小矩形R。这时p点距R的左上角坐标就会产生一个偏移,postion就表示了这个偏移。当然,position值不是等于左上角偏移,而是左下角偏移,再取负,见图1中(-1.7; -2.95)指向的两个黑色刻度标记。图1中显示的R要比包含了所有障碍物的最小矩形上、下、左、右各外扩了kPaddingPixel(5)栅格,即0.25米,position要包括这0.25。何时外扩kPaddingPixel栅格参考cartographer的PaintSubmapSlices。随着机器人移动,position会不断变化。
  • geometry_msgs/Quaternion orientation。位姿中的旋转部分。图1中header.frame_id坐标系就是世界坐标系map,表示旋转的四元数固定值(0; 0; 0; 1),即无旋转。随着机器人移动,orientation不会变化

第三部分:int8[] data

存储着栅格图中各栅格数值。理论上,每个栅格值范围是[-128, 127],实际使用时,往往会做限制,像图1中栅格,范围[-1, 100]。

对data,要额外注意放置次序。它不是通常认为的,首先放置栅格图左上角,放完0行后放1行,最后height-1行。正如图1右侧直接读取data生成的图像所示,是先存height-1行,然后height-2行,最后0行。

这种data放置次序,参考“world/map坐标系、updateOrigin、footprintCost”中“world坐标系”。

 

CreateOccupancyGridMsg

carographer提供了CreateOccupancyGridMsg方法,用于从PaintSubmapSlicesResult结构的地图painted_slices生成nav_msgs::OccupancyGrid结构的栅格图。

<cartographer_ros>\cartographer_ros\msg_conversion.cc
------
std::unique_ptr<nav_msgs::OccupancyGrid> CreateOccupancyGridMsg(
    const cartographer::io::PaintSubmapSlicesResult& painted_slices,
    const double resolution, const std::string& frame_id,
    const ros::Time& time) {
  auto occupancy_grid = absl::make_unique<nav_msgs::OccupancyGrid>();

  const int width = cairo_image_surface_get_width(painted_slices.surface.get());
  const int height =
      cairo_image_surface_get_height(painted_slices.surface.get());

  occupancy_grid->header.stamp = time;
  occupancy_grid->header.frame_id = frame_id;
  occupancy_grid->info.map_load_time = time;
  occupancy_grid->info.resolution = resolution;
  occupancy_grid->info.width = width;
  occupancy_grid->info.height = height;
  occupancy_grid->info.origin.position.x =
      -painted_slices.origin.x() * resolution;
  occupancy_grid->info.origin.position.y =
      (-height + painted_slices.origin.y()) * resolution;
  // resolution: 0.05
  // width x height: (105 x 150)(5.249, 7.500) 
  // painted_slices.origin: (34.000, 91.000)
  // ==>
  //    info.origin.position: (-1.700, -2.950)
  occupancy_grid->info.origin.position.z = 0.;
  occupancy_grid->info.origin.orientation.w = 1.;
  occupancy_grid->info.origin.orientation.x = 0.;
  occupancy_grid->info.origin.orientation.y = 0.;
  occupancy_grid->info.origin.orientation.z = 0.;

  const uint32_t* pixel_data = reinterpret_cast<uint32_t*>(
      cairo_image_surface_get_data(painted_slices.surface.get()));
  occupancy_grid->data.reserve(width * height);
  for (int y = height - 1; y >= 0; --y) {
    for (int x = 0; x < width; ++x) {
      const uint32_t packed = pixel_data[y * width + x];
      const unsigned char color = packed >> 16;
      const unsigned char observed = packed >> 8;
      const int value =
          observed == 0
              ? -1
              : ::cartographer::common::RoundToInt((1. - color / 255.) * 100.);
      CHECK_LE(-1, value);
      CHECK_GE(100, value);
      occupancy_grid->data.push_back(value);
    }
  }

  return occupancy_grid;
}

对origin.orientation,固定值(0, 0, 0, 1)。栅格值范围[-1, 100]。-1表示该栅格上的障碍物情况未知,即图1中非灰色的透明部分。

全部评论: 0

    写评论: