Esempio n. 1
0
 void FootstepPlanner::profile(FootstepAStarSolver<FootstepGraph>& solver, FootstepGraph::Ptr graph)
 {
   JSK_ROS_INFO("open list: %lu", solver.getOpenList().size());
   JSK_ROS_INFO("close list: %lu", solver.getCloseList().size());
   publishText(pub_text_,
               (boost::format("open_list: %lu\nclose list:%lu")
                % (solver.getOpenList().size()) % (solver.getCloseList().size())).str(),
               OK);
   if (rich_profiling_) {
     pcl::PointCloud<pcl::PointNormal> close_list_cloud, open_list_cloud;
     solver.openListToPointCloud(open_list_cloud);
     solver.closeListToPointCloud(close_list_cloud);
     publishPointCloud(close_list_cloud, pub_close_list_, latest_header_);
     publishPointCloud(open_list_cloud, pub_open_list_, latest_header_);
   }
 }
void SearchChargingPileManager::addLaserScanMsg(const sensor_msgs::LaserScanConstPtr& msg)
{
    size_t index_sum = (msg->angle_max - msg->angle_min)/ msg->angle_increment;
    _sourcePoints.clear();
    double angle, range;
    for (size_t index = 0; index <= index_sum; index++)
    {
        PointInfo point;
        angle = msg->angle_min + index* msg->angle_increment;
        range = msg->ranges[index];
        point.x =  range* cos(angle);
        point.y = -range* sin(angle);
        point.index = index;
        point.angle = angle;
        point.range = range;

        _sourcePoints.push_back(point);
    }

    // ===============deal with points to find objective==================
    splitLaserWithRange();                                      //calculate _breakedLaser...
    filterSplitLaser(_breakedLaserAngle, _breakedLaserRange);   //calculate _filterLaser...
    changeRangetoXY(_filterLaserAngle, _filterLaserRange);
    PointWithTimeStamp keyPoint;

    // ====== method 1 ======
    //    bool flag = findKeyPointFromLines(keyPoint);
    // ====== method 2 ======
    bool flag = recurFindKeyPointFromLines(keyPoint);


    // ===============show pointcloud============
    publishPointCloud(_filterLaserAngle, _filterLaserRange, keyPoint, flag);


    // ===============send packet================
    if (flag)
    {
        UpdateDataPacket packet;
        packet.objPosition = keyPoint;
        packet.objPosition.x += LaserXOffsetToRobot;    //change laser coordinate to robot coordinate

        packet.chargeOrderFlag = _chargeOrderFlag;
        packet.powerStatusFlag = _powerStatusFlag;

        tf::Transform transform;
        _searchFSM->update(packet, transform);
        //        std::cout << transform.getOrigin().x() << " " << transform.getOrigin().y() << std::endl;

        _vel_msg.linear.x  = _param_linear_vel* sqrt(pow(transform.getOrigin().x(), 2.0) + pow(transform.getOrigin().y(), 2.0));
        _vel_msg.angular.z = (transform.getOrigin().x() > 0.05)?
                    _param_angular_vel* atan2(transform.getOrigin().y(), transform.getOrigin().x()) :
                    _param_angular_vel* transform.getRotation().getAngle();
        //        boost::mutex::scoped_lock lock(_ctrlCmdVelMutex);
        //        _isExistValidObj = true;

    }

}
Esempio n. 3
0
void LaserPublisher::readingsCB()
{
  //printf("readingsCB(): %lu ms since last readingsCB() call.\n", readingsCallbackTime->mSecSince());
  assert(laser);
  laser->lockDevice();
  publishLaserScan();
  publishPointCloud();
  laser->unlockDevice();
  if(broadcast_tf)
    transform_broadcaster.sendTransform(tf::StampedTransform(lasertf, convertArTimeToROS(laser->getLastReadingTime()), parenttfname, tfname));
  //readingsCallbackTime->setToNow();
}
Esempio n. 4
0
void rmd::Publisher::publishDepthmapAndPointCloud() const
{
  publishDepthmap();
  publishPointCloud();
}
Esempio n. 5
0
  void FootstepPlanner::planCB(
    const jsk_footstep_msgs::PlanFootstepsGoal::ConstPtr& goal)
  {
    boost::mutex::scoped_lock lock(mutex_);
    latest_header_ = goal->goal_footstep.header;
    JSK_ROS_INFO("planCB");
    // check message sanity
    if (goal->initial_footstep.footsteps.size() == 0) {
      JSK_ROS_ERROR("no initial footstep is specified");
      as_.setPreempted();
      return;
    }
    if (goal->goal_footstep.footsteps.size() != 2) {
      JSK_ROS_ERROR("Need to specify 2 goal footsteps");
      as_.setPreempted();
      return;
    }
    if (use_pointcloud_model_ && !pointcloud_model_) {
      JSK_ROS_ERROR("No pointcloud model is yet available");
      as_.setPreempted();
      return;
    }
    //ros::WallDuration timeout(goal->timeout.expectedCycleTime().toSec());
    ros::WallDuration timeout(10.0);
    Eigen::Vector3f footstep_size(footstep_size_x_, footstep_size_y_, 0.000001);
    ////////////////////////////////////////////////////////////////////
    // set start state
    // 0 is always start
    Eigen::Affine3f start_pose;
    tf::poseMsgToEigen(goal->initial_footstep.footsteps[0].pose, start_pose);
    FootstepState::Ptr start(FootstepState::fromROSMsg(
                               goal->initial_footstep.footsteps[0],
                               footstep_size,
                               Eigen::Vector3f(resolution_x_,
                                               resolution_y_,
                                               resolution_theta_)));
    graph_->setStartState(start);
    if (project_start_state_) {
      if (!graph_->projectStart()) {
        JSK_ROS_ERROR("Failed to project start state");
        publishText(pub_text_,
                    "Failed to project start",
                    ERROR);

        as_.setPreempted();
        return;
      }
    }

    ////////////////////////////////////////////////////////////////////
    // set goal state
    jsk_footstep_msgs::Footstep left_goal, right_goal;
    for (size_t i = 0; i < goal->goal_footstep.footsteps.size(); i++) {
      FootstepState::Ptr goal_state(FootstepState::fromROSMsg(
                                      goal->goal_footstep.footsteps[i],
                                      footstep_size,
                                      Eigen::Vector3f(resolution_x_,
                                                      resolution_y_,
                                                      resolution_theta_)));
      if (goal_state->getLeg() == jsk_footstep_msgs::Footstep::LEFT) {
        graph_->setLeftGoalState(goal_state);
        left_goal = goal->goal_footstep.footsteps[i];
      }
      else if (goal_state->getLeg() == jsk_footstep_msgs::Footstep::RIGHT) {
        graph_->setRightGoalState(goal_state);
        right_goal = goal->goal_footstep.footsteps[i];
      }
      else {
        JSK_ROS_ERROR("unknown goal leg");
        as_.setPreempted();
        return;
      }
    }
    if (project_goal_state_) {
      if (!graph_->projectGoal()) {
        JSK_ROS_ERROR("Failed to project goal");
        as_.setPreempted();
        publishText(pub_text_,
                    "Failed to project goal",
                    ERROR);
        return;
      }
    }
    // set parameters
    if (use_transition_limit_) {
      graph_->setTransitionLimit(
        TransitionLimitXYZRPY::Ptr(new TransitionLimitXYZRPY(
                                     transition_limit_x_,
                                     transition_limit_y_,
                                     transition_limit_z_,
                                     transition_limit_roll_,
                                     transition_limit_pitch_,
                                     transition_limit_yaw_)));
    }
    else {
      graph_->setTransitionLimit(TransitionLimitXYZRPY::Ptr());
    }
    graph_->setLocalXMovement(local_move_x_);
    graph_->setLocalYMovement(local_move_y_);
    graph_->setLocalThetaMovement(local_move_theta_);
    graph_->setLocalXMovementNum(local_move_x_num_);
    graph_->setLocalYMovementNum(local_move_y_num_);
    graph_->setLocalThetaMovementNum(local_move_theta_num_);
    graph_->setPlaneEstimationMaxIterations(plane_estimation_max_iterations_);
    graph_->setPlaneEstimationMinInliers(plane_estimation_min_inliers_);
    graph_->setPlaneEstimationOutlierThreshold(plane_estimation_outlier_threshold_);
    graph_->setSupportCheckXSampling(support_check_x_sampling_);
    graph_->setSupportCheckYSampling(support_check_y_sampling_);
    graph_->setSupportCheckVertexNeighborThreshold(support_check_vertex_neighbor_threshold_);
    // Solver setup
    FootstepAStarSolver<FootstepGraph> solver(graph_,
                                              close_list_x_num_,
                                              close_list_y_num_,
                                              close_list_theta_num_,
                                              profile_period_,
                                              cost_weight_,
                                              heuristic_weight_);
    if (heuristic_ == "step_cost") {
      solver.setHeuristic(boost::bind(&FootstepPlanner::stepCostHeuristic, this, _1, _2));
    }
    else if (heuristic_ == "zero") {
      solver.setHeuristic(boost::bind(&FootstepPlanner::zeroHeuristic, this, _1, _2));
    }
    else if (heuristic_ == "straight") {
      solver.setHeuristic(boost::bind(&FootstepPlanner::straightHeuristic, this, _1, _2));
    }
    else if (heuristic_ == "straight_rotation") {
      solver.setHeuristic(boost::bind(&FootstepPlanner::straightRotationHeuristic, this, _1, _2));
    }
    else {
      JSK_ROS_ERROR("Unknown heuristics");
      as_.setPreempted();
      return;
    }
    solver.setProfileFunction(boost::bind(&FootstepPlanner::profile, this, _1, _2));
    ros::WallTime start_time = ros::WallTime::now();
    std::vector<SolverNode<FootstepState, FootstepGraph>::Ptr> path = solver.solve(timeout);
    ros::WallTime end_time = ros::WallTime::now();
    double planning_duration = (end_time - start_time).toSec();
    JSK_ROS_INFO_STREAM("took " << planning_duration << " sec");
    JSK_ROS_INFO_STREAM("path: " << path.size());
    if (path.size() == 0) {
      JSK_ROS_ERROR("Failed to plan path");
      publishText(pub_text_,
                  "Failed to plan",
                  ERROR);
      as_.setPreempted();
      return;
    }
    // Convert path to FootstepArray
    jsk_footstep_msgs::FootstepArray ros_path;
    ros_path.header = goal->goal_footstep.header;
    for (size_t i = 0; i < path.size(); i++) {
      ros_path.footsteps.push_back(*path[i]->getState()->toROSMsg());
    }
    // finalize path
    if (path[path.size() - 1]->getState()->getLeg() == jsk_footstep_msgs::Footstep::LEFT) {
      ros_path.footsteps.push_back(right_goal);
      ros_path.footsteps.push_back(left_goal);
    }
    else if (path[path.size() - 1]->getState()->getLeg() == jsk_footstep_msgs::Footstep::RIGHT) {
      ros_path.footsteps.push_back(left_goal);
      ros_path.footsteps.push_back(right_goal);
    }
    result_.result = ros_path;
    as_.setSucceeded(result_);

    pcl::PointCloud<pcl::PointNormal> close_list_cloud, open_list_cloud;
    solver.openListToPointCloud(open_list_cloud);
    solver.closeListToPointCloud(close_list_cloud);
    publishPointCloud(close_list_cloud, pub_close_list_, goal->goal_footstep.header);
    publishPointCloud(open_list_cloud, pub_open_list_, goal->goal_footstep.header);
    publishText(pub_text_,
                (boost::format("Planning took %f sec\n%lu path\nopen list: %lu\nclose list:%lu")
                 % planning_duration % path.size()
                 % open_list_cloud.points.size()
                 % close_list_cloud.points.size()).str(),
                OK);
  }
  bool SnapIt::processModelCylinder(jsk_pcl_ros::CallSnapIt::Request& req,
                                    jsk_pcl_ros::CallSnapIt::Response& res) {
    pcl::PointCloud<pcl::PointXYZ>::Ptr candidate_points (new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
    Eigen::Vector3f n, C_orig;
    if (!extractPointsInsideCylinder(req.request.center,
                                     req.request.direction,
                                     req.request.radius,
                                     req.request.height,
                                     inliers, n, C_orig,
                                     1.3)) {
      return false;
    }
    if (inliers->indices.size() < 3) {
      NODELET_ERROR("not enough points inside of the target_plane");
      return false;
    }
    
    geometry_msgs::PointStamped centroid;
    centroid.point.x = C_orig[0];
    centroid.point.y = C_orig[1];
    centroid.point.z = C_orig[2];
    centroid.header = req.request.header;
    
    
    pcl::ExtractIndices<pcl::PointXYZ> extract;
    extract.setInputCloud(input_);
    extract.setIndices(inliers);
    extract.filter(*candidate_points);
    
    publishPointCloud(debug_candidate_points_pub_, candidate_points);


    // first, to remove plane we estimate the plane
    pcl::ModelCoefficients::Ptr plane_coefficients (new pcl::ModelCoefficients);
    pcl::PointIndices::Ptr plane_inliers (new pcl::PointIndices);
    extractPlanePoints(candidate_points, plane_inliers, plane_coefficients,
                       n, req.request.eps_angle);
    if (plane_inliers->indices.size() == 0) {
      NODELET_ERROR ("plane estimation failed");
      return false;
    }

    // remove the points blonging to the plane
    pcl::PointCloud<pcl::PointXYZ>::Ptr points_inside_pole_wo_plane (new pcl::PointCloud<pcl::PointXYZ>);
    extract.setInputCloud (candidate_points);
    extract.setIndices (plane_inliers);
    extract.setNegative (true);
    extract.filter (*points_inside_pole_wo_plane);

    publishPointCloud(debug_candidate_points_pub2_, points_inside_pole_wo_plane);
    
    // normal estimation
    pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
    pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
    pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ> ());
    ne.setSearchMethod (tree);
    ne.setInputCloud (points_inside_pole_wo_plane);
    ne.setKSearch (50);
    ne.compute (*cloud_normals);
    
    
    // segmentation
    pcl::ModelCoefficients::Ptr cylinder_coefficients (new pcl::ModelCoefficients);
    pcl::PointIndices::Ptr cylinder_inliers (new pcl::PointIndices);
    // Create the segmentation object
    pcl::SACSegmentationFromNormals<pcl::PointXYZ, pcl::Normal> seg;
    // Optional
    seg.setOptimizeCoefficients (true);
    // Mandatory
    seg.setModelType (pcl::SACMODEL_CYLINDER);
    seg.setMethodType (pcl::SAC_RANSAC);
    seg.setRadiusLimits (0.01, req.request.radius * 1.2);
    seg.setDistanceThreshold (0.05);
    
    seg.setInputCloud(points_inside_pole_wo_plane);
    seg.setInputNormals (cloud_normals);
    seg.setMaxIterations (10000);
    seg.setNormalDistanceWeight (0.1);
    seg.setAxis(n);
    if (req.request.eps_angle != 0.0) {
      seg.setEpsAngle(req.request.eps_angle);
    }
    else {
      seg.setEpsAngle(0.35);
    }
    seg.segment (*cylinder_inliers, *cylinder_coefficients);
    if (cylinder_inliers->indices.size () == 0)
    {
      NODELET_ERROR ("Could not estimate a cylinder model for the given dataset.");
      return false;
    }

    debug_centroid_pub_.publish(centroid);
    
    pcl::PointCloud<pcl::PointXYZ>::Ptr cylinder_points (new pcl::PointCloud<pcl::PointXYZ>);
    extract.setInputCloud (points_inside_pole_wo_plane);
    extract.setIndices (cylinder_inliers);
    extract.setNegative (false);
    extract.filter (*cylinder_points);

    publishPointCloud(debug_candidate_points_pub3_, cylinder_points);

    Eigen::Vector3f n_prime;
    Eigen::Vector3f C_new;
    for (size_t i = 0; i < 3; i++) {
      C_new[i] = cylinder_coefficients->values[i];
      n_prime[i] = cylinder_coefficients->values[i + 3];
    }

    double radius = fabs(cylinder_coefficients->values[6]);
    // inorder to compute centroid, we project all the points to the center line.
    // and after that, get the minimum and maximum points in the coordinate system of the center line
    double min_alpha = DBL_MAX;
    double max_alpha = -DBL_MAX;
    for (size_t i = 0; i < cylinder_points->points.size(); i++ ) {
      pcl::PointXYZ q = cylinder_points->points[i];
      double alpha = (q.getVector3fMap() - C_new).dot(n_prime);
      if (alpha < min_alpha) {
        min_alpha = alpha;
      }
      if (alpha > max_alpha) {
        max_alpha = alpha;
      }
    }
    // the center of cylinder
    Eigen::Vector3f C_new_prime = C_new + (max_alpha + min_alpha) / 2.0 * n_prime;
    
    Eigen::Vector3f n_cross = n.cross(n_prime);
    if (n.dot(n_prime)) {
      n_cross = - n_cross;
    }
    double theta = asin(n_cross.norm());
    Eigen::Quaternionf trans (Eigen::AngleAxisf(theta, n_cross.normalized()));
    Eigen::Vector3f C = trans * C_orig;
    Eigen::Affine3f A = Eigen::Translation3f(C) * Eigen::Translation3f(C_new_prime - C) * trans * Eigen::Translation3f(C_orig).inverse();
    tf::poseEigenToMsg((Eigen::Affine3d)A, res.transformation);

    geometry_msgs::PointStamped centroid_transformed;
    centroid_transformed.point.x = C_new_prime[0];
    centroid_transformed.point.y = C_new_prime[1];
    centroid_transformed.point.z = C_new_prime[2];
    centroid_transformed.header = req.request.header;
    debug_centroid_after_trans_pub_.publish(centroid_transformed);

    // publish marker
    visualization_msgs::Marker marker;
    marker.type = visualization_msgs::Marker::CYLINDER;
    marker.scale.x = radius;
    marker.scale.y = radius;
    marker.scale.z = (max_alpha - min_alpha);
    marker.pose.position.x = C_new_prime[0];
    marker.pose.position.y = C_new_prime[1];
    marker.pose.position.z = C_new_prime[2];

    // n_prime -> z
    // n_cross.normalized() -> x
    Eigen::Vector3f z_axis = n_prime.normalized();
    Eigen::Vector3f y_axis = n_cross.normalized();
    Eigen::Vector3f x_axis = (y_axis.cross(z_axis)).normalized();
    Eigen::Matrix3f M;
    for (size_t i = 0; i < 3; i++) {
      M(i, 0) = x_axis[i];
      M(i, 1) = y_axis[i];
      M(i, 2) = z_axis[i];
    }
    
    Eigen::Quaternionf q (M);
    marker.pose.orientation.x = q.x();
    marker.pose.orientation.y = q.y();
    marker.pose.orientation.z = q.z();
    marker.pose.orientation.w = q.w();
    marker.color.g = 1.0;
    marker.color.a = 1.0;
    marker.header = input_header_;
    marker_pub_.publish(marker);
    
    return true;
  }
  bool SnapIt::processModelPlane(jsk_pcl_ros::CallSnapIt::Request& req,
                                 jsk_pcl_ros::CallSnapIt::Response& res) {
    // first build plane model
    geometry_msgs::PolygonStamped target_plane = req.request.target_plane;
    // check the size of the points
    if (target_plane.polygon.points.size() < 3) {
      NODELET_ERROR("not enough points included in target_plane");
      return false;
    }
    pcl::PointCloud<pcl::PointXYZ>::Ptr points_inside_pole (new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointIndices::Ptr inliers(new pcl::PointIndices);
    EigenVector3fVector points;
    Eigen::Vector3f n, p;
    if (!extractPointsInsidePlanePole(target_plane, inliers, points, n, p)) {
      return false;
    }

    if (inliers->indices.size() < 3) {
      NODELET_ERROR("not enough points inside of the target_plane");
      return false;
    }
    
    pcl::ExtractIndices<pcl::PointXYZ> extract;
    extract.setInputCloud(input_);
    extract.setIndices(inliers);
    extract.filter(*points_inside_pole);

    publishPointCloud(debug_candidate_points_pub_, points_inside_pole);
    
    // estimate plane
    
    pcl::ModelCoefficients::Ptr plane_coefficients (new pcl::ModelCoefficients);
    pcl::PointIndices::Ptr plane_inliers (new pcl::PointIndices);
    extractPlanePoints(points_inside_pole, plane_inliers, plane_coefficients,
                       n, req.request.eps_angle);

    if (plane_inliers->indices.size () == 0)
    {
      NODELET_ERROR ("Could not estimate a planar model for the given dataset.");
      return false;
    }

    // extract plane points
    pcl::PointCloud<pcl::PointXYZ>::Ptr plane_points (new pcl::PointCloud<pcl::PointXYZ>);
    pcl::ProjectInliers<pcl::PointXYZ> proj;
    proj.setModelType (pcl::SACMODEL_PLANE);
    proj.setIndices (plane_inliers);
    proj.setInputCloud (points_inside_pole);
    proj.setModelCoefficients (plane_coefficients);
    proj.filter (*plane_points);
    publishPointCloud(debug_candidate_points_pub3_, plane_points);
    
    // next, compute convexhull and centroid
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull (new pcl::PointCloud<pcl::PointXYZ>);
    pcl::ConcaveHull<pcl::PointXYZ> chull;
    chull.setInputCloud (plane_points);
    chull.setDimension(2);
    chull.setAlpha (0.1);
    
    chull.reconstruct (*cloud_hull);

    if (cloud_hull->points.size() < 3) {
      NODELET_ERROR("failed to estimate convex hull");
      return false;
    }
    publishConvexHullMarker(cloud_hull);
    
    Eigen::Vector4f C_new_4f;
    pcl::compute3DCentroid(*cloud_hull, C_new_4f);
    Eigen::Vector3f C_new;
    for (size_t i = 0; i < 3; i++) {
      C_new[i] = C_new_4f[i];
    }
    
    Eigen::Vector3f n_prime;
    n_prime[0] = plane_coefficients->values[0];
    n_prime[1] = plane_coefficients->values[1];
    n_prime[2] = plane_coefficients->values[2];
    plane_coefficients->values[3] = plane_coefficients->values[3] / n_prime.norm();
    n_prime.normalize();
    
    if (n_prime.dot(n) < 0) {
      n_prime = - n_prime;
      plane_coefficients->values[3] = - plane_coefficients->values[3];
    }
    
    Eigen::Vector3f n_cross = n.cross(n_prime);
    double theta = asin(n_cross.norm());

    Eigen::Quaternionf trans (Eigen::AngleAxisf(theta, n_cross.normalized()));
    
    // compute C
    Eigen::Vector3f C_orig(0, 0, 0);
    for (size_t i = 0; i < points.size(); i++) {
      C_orig = C_orig + points[i];
    }
    C_orig = C_orig / points.size();
    // compute C
    Eigen::Vector3f C = trans * C_orig;
    

    Eigen::Affine3f A = Eigen::Translation3f(C) * Eigen::Translation3f(C_new - C) * trans * Eigen::Translation3f(C_orig).inverse();
    tf::poseEigenToMsg((Eigen::Affine3d)A, res.transformation);

    geometry_msgs::PointStamped centroid;
    centroid.point.x = C_orig[0];
    centroid.point.y = C_orig[1];
    centroid.point.z = C_orig[2];
    centroid.header = target_plane.header;
    debug_centroid_pub_.publish(centroid);

    geometry_msgs::PointStamped centroid_transformed;
    centroid_transformed.point.x = C_new[0];
    centroid_transformed.point.y = C_new[1];
    centroid_transformed.point.z = C_new[2];
    centroid_transformed.header = target_plane.header;
    debug_centroid_after_trans_pub_.publish(centroid_transformed);
    
    return true;
  }
void XtionGrabber::read_thread()
{
	fd_set fds;

	while(!m_shouldExit)
	{
		FD_ZERO(&fds);
		FD_SET(m_depth_fd, &fds);
		FD_SET(m_color_fd, &fds);

		int ret = select(std::max(m_depth_fd, m_color_fd)+1, &fds, 0, 0, 0);

		if(ret < 0)
		{
			perror("Could not select()");
			return;
		}

		if(FD_ISSET(m_color_fd, &fds))
		{
			v4l2_buffer buf;
			memset(&buf, 0, sizeof(buf));
			buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			buf.memory = V4L2_MEMORY_USERPTR;

			if(ioctl(m_color_fd, VIDIOC_DQBUF, &buf) != 0)
			{
				if(errno == EAGAIN)
					continue;
				perror("Could not dequeue buffer");
				return;
			}

			ColorBuffer* buffer = &m_color_buffers[buf.index];

			sensor_msgs::ImagePtr img = m_color_pool->create();
			img->width = m_colorWidth;
			img->height = m_colorHeight;
			img->step = img->width * 4;
			img->data.resize(img->step * img->height);
			img->header.stamp = timeFromTimeval(buf.timestamp);
			img->header.frame_id = "/camera_optical";

			img->encoding = sensor_msgs::image_encodings::BGRA8;

#if HAVE_LIBYUV
			libyuv::ConvertToARGB(
				buffer->data.data(), buffer->data.size(),
				img->data.data(),
				m_colorWidth*4, 0, 0, m_colorWidth, m_colorHeight, m_colorWidth, m_colorHeight,
				libyuv::kRotate0, libyuv::FOURCC_UYVY
			);
#else
			uint32_t* dptr = (uint32_t*)img->data.data();

			for(size_t y = 0; y < img->height; ++y)
			{
					for(size_t x = 0; x < img->width-1; x += 2)
					{
							unsigned char* base = &buffer->data[y*m_colorWidth*2+x*2];
							float y1 = base[1];
							float u  = base[0];
							float y2 = base[3];
							float v  = base[2];

							uint32_t rgb1 = yuv(y1, u, v);
							uint32_t rgb2 = yuv(y2, u, v);

							dptr[y*img->width + x + 0] = rgb1;
							dptr[y*img->width + x + 1] = rgb2;
					}
			}
#endif

			m_lastColorImage = img;
			m_lastColorSeq = buf.sequence;

			m_color_info.header.stamp = img->header.stamp;
			m_pub_color.publish(img, boost::make_shared<sensor_msgs::CameraInfo>(m_color_info));

			if(ioctl(m_color_fd, VIDIOC_QBUF, &buffer->buf) != 0)
			{
				perror("Could not queue buffer");
				return;
			}
		}

		if(FD_ISSET(m_depth_fd, &fds))
		{
			v4l2_buffer buf;
			memset(&buf, 0, sizeof(buf));
			buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			buf.memory = V4L2_MEMORY_USERPTR;

			if(ioctl(m_depth_fd, VIDIOC_DQBUF, &buf) != 0)
			{
				if(errno == EAGAIN)
					continue;
				perror("Could not dequeue buffer");
				return;
			}

			DepthBuffer* buffer = &m_depth_buffers[buf.index];

			buffer->image->header.stamp = timeFromTimeval(buf.timestamp);

			m_lastDepthImage = buffer->image;
			m_lastDepthSeq = buf.sequence;

			m_depth_info.header.stamp = buffer->image->header.stamp;
			m_pub_depth.publish(buffer->image, boost::make_shared<sensor_msgs::CameraInfo>(m_depth_info));

			buffer->image.reset();

			buffer->image = createDepthImage();
			buffer->buf.m.userptr = (long unsigned int)buffer->image->data.data();

			if(ioctl(m_depth_fd, VIDIOC_QBUF, &buffer->buf) != 0)
			{
				perror("Could not queue buffer");
				return;
			}
		}

		if(m_lastColorSeq == m_lastDepthSeq)
		{
			if(m_pub_cloud.getNumSubscribers() != 0)
				publishPointCloud(m_lastDepthImage, &m_cloudGenerator, &m_pub_cloud);

			if(m_pub_filledCloud.getNumSubscribers() != 0)
			{
				sensor_msgs::ImagePtr filledDepth = m_depthFiller.fillDepth(
					m_lastDepthImage, m_lastColorImage
				);
				publishPointCloud(filledDepth, &m_filledCloudGenerator, &m_pub_filledCloud);
			}
		}
	}

	fprintf(stderr, "read thread exit now\n");
}
void LslidarN301Decoder::packetCallback(
    const lslidar_n301_msgs::LslidarN301PacketConstPtr& msg) {
//  ROS_WARN("packetCallBack");
  // Convert the msg to the raw packet type.
  const RawPacket* raw_packet = (const RawPacket*) (&(msg->data[0]));

  // Check if the packet is valid
  if (!checkPacketValidity(raw_packet)) return;

  // Decode the packet
  decodePacket(raw_packet);

  // Find the start of a new revolution
  //    If there is one, new_sweep_start will be the index of the start firing,
  //    otherwise, new_sweep_start will be FIRINGS_PER_PACKET.
  size_t new_sweep_start = 0;
  do {
//    if (firings[new_sweep_start].firing_azimuth < last_azimuth) break;
    if (fabs(firings[new_sweep_start].firing_azimuth - last_azimuth) > M_PI) break;
    else {
      last_azimuth = firings[new_sweep_start].firing_azimuth;
      ++new_sweep_start;
    }
  } while (new_sweep_start < FIRINGS_PER_PACKET);
//  ROS_WARN("new_sweep_start %d", new_sweep_start);

  // The first sweep may not be complete. So, the firings with
  // the first sweep will be discarded. We will wait for the
  // second sweep in order to find the 0 azimuth angle.
  size_t start_fir_idx = 0;
  size_t end_fir_idx = new_sweep_start;
  if (is_first_sweep &&
      new_sweep_start == FIRINGS_PER_PACKET) {
    // The first sweep has not ended yet.
    return;
  } else {
    if (is_first_sweep) {
      is_first_sweep = false;
      start_fir_idx = new_sweep_start;
      end_fir_idx = FIRINGS_PER_PACKET;
      sweep_start_time = msg->stamp.toSec() + 
        FIRING_TOFFSET * (end_fir_idx-start_fir_idx) * 1e-6;
    }
  }

  for (size_t fir_idx = start_fir_idx; fir_idx < end_fir_idx; ++fir_idx) {
    for (size_t scan_idx = 0; scan_idx < SCANS_PER_FIRING; ++scan_idx) {
      // Check if the point is valid.
      if (!isPointInRange(firings[fir_idx].distance[scan_idx])) continue;

      // Convert the point to xyz coordinate
      size_t table_idx = floor(firings[fir_idx].azimuth[scan_idx]*1000.0+0.5);
      //cout << table_idx << endl;
      double cos_azimuth = cos_azimuth_table[table_idx];
      double sin_azimuth = sin_azimuth_table[table_idx];

      //double x = firings[fir_idx].distance[scan_idx] *
      //  cos_scan_altitude[scan_idx] * sin(firings[fir_idx].azimuth[scan_idx]);
      //double y = firings[fir_idx].distance[scan_idx] *
      //  cos_scan_altitude[scan_idx] * cos(firings[fir_idx].azimuth[scan_idx]);
      //double z = firings[fir_idx].distance[scan_idx] *
      //  sin_scan_altitude[scan_idx];

      double x = firings[fir_idx].distance[scan_idx] *
        cos_scan_altitude[scan_idx] * sin_azimuth;
      double y = firings[fir_idx].distance[scan_idx] *
        cos_scan_altitude[scan_idx] * cos_azimuth;
      double z = firings[fir_idx].distance[scan_idx] *
        sin_scan_altitude[scan_idx];

      double x_coord = y;
      double y_coord = -x;
      double z_coord = z;

      // Compute the time of the point
      double time = packet_start_time +
        FIRING_TOFFSET*fir_idx + DSR_TOFFSET*scan_idx;

      // Remap the index of the scan
      int remapped_scan_idx = scan_idx%2 == 0 ? scan_idx/2 : scan_idx/2+8;
      sweep_data->scans[remapped_scan_idx].points.push_back(
          lslidar_n301_msgs::LslidarN301Point());

      lslidar_n301_msgs::LslidarN301Point& new_point =		// new_point 为push_back最后一个的引用
        sweep_data->scans[remapped_scan_idx].points[
        sweep_data->scans[remapped_scan_idx].points.size()-1];

      // Pack the data into point msg
      new_point.time = time;
      new_point.x = x_coord;
      new_point.y = y_coord;
      new_point.z = z_coord;
      new_point.azimuth = firings[fir_idx].azimuth[scan_idx];
      new_point.distance = firings[fir_idx].distance[scan_idx];
      new_point.intensity = firings[fir_idx].intensity[scan_idx];
    }
  }

  packet_start_time += FIRING_TOFFSET * (end_fir_idx-start_fir_idx);

  // A new sweep begins
  if (end_fir_idx != FIRINGS_PER_PACKET) {	
//	ROS_WARN("A new sweep begins");
    // Publish the last revolution
    //sweep_data->header.stamp = ros::Time(sweep_start_time);
    sweep_data->header.stamp = ros::Time();    
    sweep_pub.publish(sweep_data);
    if (publish_point_cloud) publishPointCloud();
    publishScan();
    sweep_data = lslidar_n301_msgs::LslidarN301SweepPtr(
        new lslidar_n301_msgs::LslidarN301Sweep());

    // Prepare the next revolution
    sweep_start_time = msg->stamp.toSec() + 
      FIRING_TOFFSET * (end_fir_idx-start_fir_idx) * 1e-6;
    packet_start_time = 0.0;
    last_azimuth = firings[FIRINGS_PER_PACKET-1].firing_azimuth;

    start_fir_idx = end_fir_idx;
    end_fir_idx = FIRINGS_PER_PACKET;

    for (size_t fir_idx = start_fir_idx; fir_idx < end_fir_idx; ++fir_idx) {
      for (size_t scan_idx = 0; scan_idx < SCANS_PER_FIRING; ++scan_idx) {
        // Check if the point is valid.
        if (!isPointInRange(firings[fir_idx].distance[scan_idx])) continue;

        // Convert the point to xyz coordinate
        size_t table_idx = floor(firings[fir_idx].azimuth[scan_idx]*1000.0+0.5);
        //cout << table_idx << endl;
        double cos_azimuth = cos_azimuth_table[table_idx];
        double sin_azimuth = sin_azimuth_table[table_idx];

        //double x = firings[fir_idx].distance[scan_idx] *
        //  cos_scan_altitude[scan_idx] * sin(firings[fir_idx].azimuth[scan_idx]);
        //double y = firings[fir_idx].distance[scan_idx] *
        //  cos_scan_altitude[scan_idx] * cos(firings[fir_idx].azimuth[scan_idx]);
        //double z = firings[fir_idx].distance[scan_idx] *
        //  sin_scan_altitude[scan_idx];

        double x = firings[fir_idx].distance[scan_idx] *
          cos_scan_altitude[scan_idx] * sin_azimuth;
        double y = firings[fir_idx].distance[scan_idx] *
          cos_scan_altitude[scan_idx] * cos_azimuth;
        double z = firings[fir_idx].distance[scan_idx] *
          sin_scan_altitude[scan_idx];

        double x_coord = y;
        double y_coord = -x;
        double z_coord = z;

        // Compute the time of the point
        double time = packet_start_time + 
          FIRING_TOFFSET*(fir_idx-start_fir_idx) + DSR_TOFFSET*scan_idx;

        // Remap the index of the scan
        int remapped_scan_idx = scan_idx%2 == 0 ? scan_idx/2 : scan_idx/2+8;
        sweep_data->scans[remapped_scan_idx].points.push_back(
            lslidar_n301_msgs::LslidarN301Point());
        lslidar_n301_msgs::LslidarN301Point& new_point =
          sweep_data->scans[remapped_scan_idx].points[
          sweep_data->scans[remapped_scan_idx].points.size()-1];

        // Pack the data into point msg
        new_point.time = time;
        new_point.x = x_coord;
        new_point.y = y_coord;
        new_point.z = z_coord;
        new_point.azimuth = firings[fir_idx].azimuth[scan_idx];
        new_point.distance = firings[fir_idx].distance[scan_idx];
        new_point.intensity = firings[fir_idx].intensity[scan_idx];
      }
    }

    packet_start_time += FIRING_TOFFSET * (end_fir_idx-start_fir_idx);
  }
//  ROS_WARN("pack end");
  return;
}