/**
 * @return either one of control_msgs::FollowJointTrajectoryResult, or PREEMPT_REQUESTED
 */
int JointTrajectoryActionController::executeCommon(const trajectory_msgs::JointTrajectory &trajectory,
                                                   boost::function<bool()> isPreemptRequested)
{
  if (!setsEqual(joints_, trajectory.joint_names))
  {
    ROS_ERROR("Joints on incoming goal don't match our joints");
    for (size_t i = 0; i < trajectory.joint_names.size(); i++)
    {
      ROS_INFO("  incoming joint %d: %s", (int)i, trajectory.joint_names[i].c_str());
    }
    for (size_t i = 0; i < joints_.size(); i++)
    {
      ROS_INFO("  our joint      %d: %s", (int)i, joints_[i].c_str());
    }
    return control_msgs::FollowJointTrajectoryResult::INVALID_JOINTS;
  }

  if (isPreemptRequested())
  {
    ROS_WARN("New action goal already seems to have been canceled!");
    return PREEMPT_REQUESTED;
  }

  // make sure the katana is stopped
  reset_trajectory_and_stop();

  // ------ If requested, performs a stop
  if (trajectory.points.empty())
  {
    // reset_trajectory_and_stop();
    return control_msgs::FollowJointTrajectoryResult::SUCCESSFUL;
  }

  // calculate new trajectory
  boost::shared_ptr<SpecifiedTrajectory> new_traj = calculateTrajectory(trajectory);
  if (!new_traj)
  {
    ROS_ERROR("Could not calculate new trajectory, aborting");
    return control_msgs::FollowJointTrajectoryResult::INVALID_GOAL;
  }
  if (!validTrajectory(*new_traj))
  {
    ROS_ERROR("Computed trajectory did not fulfill all constraints!");
    return control_msgs::FollowJointTrajectoryResult::INVALID_GOAL;
  }
  current_trajectory_ = new_traj;

  // sleep until 0.5 seconds before scheduled start
  ROS_DEBUG_COND(
      trajectory.header.stamp > ros::Time::now(),
      "Sleeping for %f seconds before start of trajectory", (trajectory.header.stamp - ros::Time::now()).toSec());
  ros::Rate rate(10);
  while ((trajectory.header.stamp - ros::Time::now()).toSec() > 0.5)
  {
    if (isPreemptRequested() || !ros::ok())
    {
      ROS_WARN("Goal canceled by client while waiting until scheduled start, aborting!");
      return PREEMPT_REQUESTED;
    }
    rate.sleep();
  }

  ROS_INFO("Sending trajectory to Katana arm...");
  bool success = katana_->executeTrajectory(new_traj, isPreemptRequested);
  if (!success)
  {
    ROS_ERROR("Problem while transferring trajectory to Katana arm, aborting");
    return control_msgs::FollowJointTrajectoryResult::PATH_TOLERANCE_VIOLATED;
  }

  ROS_INFO("Waiting until goal reached...");
  ros::Rate goalWait(10);
  while (ros::ok())
  {
    // always have to call this before calling someMotorCrashed() or allJointsReady()
    katana_->refreshMotorStatus();

    if (katana_->someMotorCrashed())
    {
      ROS_ERROR("Some motor has crashed! Aborting trajectory...");
      return control_msgs::FollowJointTrajectoryResult::PATH_TOLERANCE_VIOLATED;
    }

    // all joints are idle
    if (katana_->allJointsReady() && allJointsStopped())
    {
      // // make sure the joint positions are updated before checking for goalReached()
      // --> this isn't necessary because refreshEncoders() is periodically called
      //     by KatanaNode. Leaving it out saves us some Katana bandwidth.
      // katana_->refreshEncoders();

      if (goalReached())
      {
        // joints are idle and we are inside goal constraints. yippie!
        ROS_INFO("Goal reached.");
        return control_msgs::FollowJointTrajectoryResult::SUCCESSFUL;
      }
      else
      {
        ROS_ERROR("Joints are idle and motors are not crashed, but we did not reach the goal position! WTF?");
        return control_msgs::FollowJointTrajectoryResult::GOAL_TOLERANCE_VIOLATED;
      }
    }

    if (isPreemptRequested())
    {
      ROS_WARN("Goal canceled by client while waiting for trajectory to finish, aborting!");
      return PREEMPT_REQUESTED;
    }

    goalWait.sleep();
  }

  // this part is only reached when node is shut down
  return PREEMPT_REQUESTED;
}
Esempio n. 2
0
void ExploreFrontier::findFrontiers() {
  frontiers_.clear();

  const size_t w = costmap_->getSizeInCellsX();
  const size_t h = costmap_->getSizeInCellsY();
  const size_t size = w * h;

  map_.info.width = w;
  map_.info.height = h;
  map_.data.resize(size);
  map_.info.resolution = costmap_->getResolution();
  map_.info.origin.position.x = costmap_->getOriginX();
  map_.info.origin.position.y = costmap_->getOriginY();

  // lock as we are accessing raw underlying map
  auto *mutex = costmap_->getMutex();
  std::unique_lock<costmap_2d::Costmap2D::mutex_t> lock(*mutex);

  // Find all frontiers (open cells next to unknown cells).
  const unsigned char* map = costmap_->getCharMap();
  ROS_DEBUG_COND(!map, "no map available");
  for (size_t i = 0; i < size; ++i) {
//    //get the world point for the index
//    unsigned int mx, my;
//    costmap.indexToCells(i, mx, my);
//    geometry_msgs::Point p;
//    costmap.mapToWorld(mx, my, p.x, p.y);
//
    //check if the point has valid potential and is next to unknown space
//    bool valid_point = planner_->validPointPotential(p);
    bool valid_point = (map[i] < costmap_2d::LETHAL_OBSTACLE);
    // ROS_DEBUG_COND(!valid_point, "invalid point %u", map[i]);

    if ((valid_point && map) &&
      (((i+1 < size) && (map[i+1] == costmap_2d::NO_INFORMATION)) ||
       ((i-1 < size) && (map[i-1] == costmap_2d::NO_INFORMATION)) ||
       ((i+w < size) && (map[i+w] == costmap_2d::NO_INFORMATION)) ||
       ((i-w < size) && (map[i-w] == costmap_2d::NO_INFORMATION))))
    {
      ROS_DEBUG_THROTTLE(30, "found suitable point");
      map_.data[i] = -128;
    } else {
      map_.data[i] = -127;
    }
  }

  // Clean up frontiers detected on separate rows of the map
  for (size_t y = 0, i = h-1; y < w; ++y) {
    ROS_DEBUG_THROTTLE(30, "cleaning cell %lu", i);
    map_.data[i] = -127;
    i += h;
  }

  // Group adjoining map_ pixels
  signed char segment_id = 127;
  std::vector<std::vector<FrontierPoint>> segments;
  for (size_t i = 0; i < size; i++) {
    if (map_.data[i] == -128) {
      ROS_DEBUG_THROTTLE(30, "adjoining on %lu", i);
      std::vector<size_t> neighbors;
      std::vector<FrontierPoint> segment;
      neighbors.push_back(i);

      // claim all neighbors
      while (!neighbors.empty()) {
        ROS_DEBUG_THROTTLE(30, "got %lu neighbors", neighbors.size());
        size_t idx = neighbors.back();
        neighbors.pop_back();
        map_.data[idx] = segment_id;

        tf::Vector3 tot(0,0,0);
        size_t c = 0;
        if (idx+1 < size && map[idx+1] == costmap_2d::NO_INFORMATION) {
          tot += tf::Vector3(1,0,0);
          ++c;
        }
        if (idx-1 < size && map[idx-1] == costmap_2d::NO_INFORMATION) {
          tot += tf::Vector3(-1,0,0);
          ++c;
        }
        if (idx+w < size && map[idx+w] == costmap_2d::NO_INFORMATION) {
          tot += tf::Vector3(0,1,0);
          ++c;
        }
        if (idx-w < size && map[idx-w] == costmap_2d::NO_INFORMATION) {
          tot += tf::Vector3(0,-1,0);
          ++c;
        }

        if(!(c > 0)) {
          ROS_ERROR("assertion failed. corrupted costmap?");
          ROS_DEBUG("c is %lu", c);
          continue;
        }

        segment.push_back(FrontierPoint(idx, tot / c));

        // consider 8 neighborhood
        if (idx-1 < size && map_.data[idx-1] == -128)
          neighbors.push_back(idx-1);
        if (idx+1 < size && map_.data[idx+1] == -128)
          neighbors.push_back(idx+1);
        if (idx-w < size && map_.data[idx-w] == -128)
          neighbors.push_back(idx-w);
        if (idx-w+1 < size && map_.data[idx-w+1] == -128)
          neighbors.push_back(idx-w+1);
        if (idx-w-1 < size && map_.data[idx-w-1] == -128)
          neighbors.push_back(idx-w-1);
        if (idx+w < size && map_.data[idx+w] == -128)
          neighbors.push_back(idx+w);
        if (idx+w+1 < size && map_.data[idx+w+1] == -128)
          neighbors.push_back(idx+w+1);
        if (idx+w-1 < size && map_.data[idx+w-1] == -128)
          neighbors.push_back(idx+w-1);
      }

      segments.push_back(std::move(segment));
      segment_id--;
      if (segment_id < -127)
        break;
    }
  }

  // no longer accessing map
  lock.unlock();

  int num_segments = 127 - segment_id;
  if (num_segments <= 0) {
    ROS_DEBUG("#segments is <0, no frontiers found");
    return;
  }

  for (auto& segment : segments) {
    Frontier frontier;
    size_t segment_size = segment.size();

    //we want to make sure that the frontier is big enough for the robot to fit through
    if (segment_size * costmap_->getResolution() < costmap_client_->getInscribedRadius()) {
      ROS_DEBUG_THROTTLE(30, "some frontiers were small");
      continue;
    }

    float x = 0, y = 0;
    tf::Vector3 d(0,0,0);

    for (const auto& frontier_point : segment) {
      d += frontier_point.d;
      size_t idx = frontier_point.idx;
      x += (idx % w);
      y += (idx / w);
    }
    d = d / segment_size;
    frontier.pose.position.x = map_.info.origin.position.x + map_.info.resolution * (x / segment_size);
    frontier.pose.position.y = map_.info.origin.position.y + map_.info.resolution * (y / segment_size);
    frontier.pose.position.z = 0.0;

    frontier.pose.orientation = tf::createQuaternionMsgFromYaw(atan2(d.y(), d.x()));
    frontier.size = segment_size;

    frontiers_.push_back(std::move(frontier));
  }

}