机器人视觉项目:视觉检测识别+机器人跟随(22)

机器人调试

ros turtle_floower人体跟随

#include 
#include 
#include 
#include 
#include 
#include 
#include 
​
#include "dynamic_reconfigure/server.h"
#include "turtlebot_follower/FollowerConfig.h"
​
#include 
​
​
namespace turtlebot_follower
{
​
//* The turtlebot follower nodelet.
/**
 * The turtlebot follower nodelet. Subscribes to point clouds
 * from the 3dsensor, processes them, and publishes command vel
 * messages.
 */
class TurtlebotFollower : public nodelet::Nodelet
{
public:
  /*!
   * @brief The constructor for the follower.
   * Constructor for the follower.
   */
  TurtlebotFollower() : min_y_(0.1), max_y_(0.5),
                        min_x_(-0.2), max_x_(0.2),
                        max_z_(0.8), goal_z_(0.6),
                        z_scale_(1.0), x_scale_(5.0)
  {
​
  }
​
  ~TurtlebotFollower()
  {
    delete config_srv_;
  }
​
private:
  double min_y_; /**< The minimum y position of the points in the box. */
  double max_y_; /**< The maximum y position of the points in the box. */
  double min_x_; /**< The minimum x position of the points in the box. */
  double max_x_; /**< The maximum x position of the points in the box. */
  double max_z_; /**< The maximum z position of the points in the box. 框中 点的最大z位置,以上四个字段用来设置框的大小*/
  double goal_z_; /**< The distance away from the robot to hold the centroid 离机器人的距离,以保持质心*/
  double z_scale_; /**< The scaling factor for translational robot speed 移动机器人速度的缩放系数*/
  double x_scale_; /**< The scaling factor for rotational robot speed 旋转机器人速度的缩放系数*/
  bool   enabled_; /**< Enable/disable following; just prevents motor commands 启用/禁用追踪; 只是阻止电机命令,置为false后,机器人不会移动,/mobile_base/mobile_base_controller/cmd_vel topic 为空*/
​
  // Service for start/stop following
  ros::ServiceServer switch_srv_;
​
  // Dynamic reconfigure server 动态配置服务
  dynamic_reconfigure::Server* config_srv_;
​
  /*!
   * @brief OnInit method from node handle.
   * OnInit method from node handle. Sets up the parameters
   * and topics.
   * 初始化handle,参数,和话题
   */
  virtual void onInit()
  {
    ros::NodeHandle& nh = getNodeHandle();
    ros::NodeHandle& private_nh = getPrivateNodeHandle();
   //从参数服务器获取设置的参数(launch文件中设置数值)
    private_nh.getParam("min_y", min_y_);
    private_nh.getParam("max_y", max_y_);
    private_nh.getParam("min_x", min_x_);
    private_nh.getParam("max_x", max_x_);
    private_nh.getParam("max_z", max_z_);
    private_nh.getParam("goal_z", goal_z_);
    private_nh.getParam("z_scale", z_scale_);
    private_nh.getParam("x_scale", x_scale_);
    private_nh.getParam("enabled", enabled_);
    //设置机器人移动的话题(用于机器人移动):/mobile_base/mobile_base_controller/cmd_vel(换成机器人的移动topic)
    cmdpub_ = private_nh.advertise ("/mobile_base/mobile_base_controller/cmd_vel", 1);
​
    markerpub_ = private_nh.advertise("marker",1);
    bboxpub_ = private_nh.advertise("bbox",1);
    sub_= nh.subscribe("depth/image_rect", 1, &TurtlebotFollower::imagecb, this);
​
    switch_srv_ = private_nh.advertiseService("change_state", &TurtlebotFollower::changeModeSrvCb, this);
​
    config_srv_ = new dynamic_reconfigure::Server(private_nh);
    dynamic_reconfigure::Server::CallbackType f =
        boost::bind(&TurtlebotFollower::reconfigure, this, _1, _2);
    config_srv_->setCallback(f);
  }
​
//设置默认值,详见catkin_ws/devel/include/turtlrbot_follower/FollowerConfig.h
  void reconfigure(turtlebot_follower::FollowerConfig &config, uint32_t level)
  {
    min_y_ = config.min_y;
    max_y_ = config.max_y;
    min_x_ = config.min_x;
    max_x_ = config.max_x;
    max_z_ = config.max_z;
    goal_z_ = config.goal_z;
    z_scale_ = config.z_scale;
    x_scale_ = config.x_scale;
  }
​
  /*!
   * @brief Callback for point clouds.
   * Callback for depth images. It finds the centroid
   * of the points in a box in the center of the image. 
   * 它找到图像中心框中的点的质心
   * Publishes cmd_vel messages with the goal from the image.
   * 发布图像中目标的cmd_vel 消息
   * @param cloud The point cloud message.
   * 参数:点云的消息
   */
  void imagecb(const sensor_msgs::ImageConstPtr& depth_msg)
  {
​
    // Precompute the sin function for each row and column wangchao预计算每行每列的正弦函数
    uint32_t image_width = depth_msg->width;
    ROS_INFO_THROTTLE(1, "image_width=%d", image_width);
    float x_radians_per_pixel = 60.0/57.0/image_width;//每个像素的弧度
    float sin_pixel_x[image_width];
    for (int x = 0; x < image_width; ++x) {
      //求出正弦值
      sin_pixel_x[x] = sin((x - image_width/ 2.0)  * x_radians_per_pixel);
    }
​
    uint32_t image_height = depth_msg->height;
    float y_radians_per_pixel = 45.0/57.0/image_width;
    float sin_pixel_y[image_height];
    for (int y = 0; y < image_height; ++y) {
      // Sign opposite x for y up values 
      sin_pixel_y[y] = sin((image_height/ 2.0 - y)  * y_radians_per_pixel);
    }
​
    //X,Y,Z of the centroid 质心的xyz
    float x = 0.0;
    float y = 0.0;
    float z = 1e6;
    //Number of points observed 观察的点数
    unsigned int n = 0;
​
    //Iterate through all the points in the region and find the average of the position 迭代通过该区域的所有点,找到位置的平均值
    const float* depth_row = reinterpret_cast(&depth_msg->data[0]);
    int row_step = depth_msg->step / sizeof(float);
    for (int v = 0; v < (int)depth_msg->height; ++v, depth_row += row_step)
    {
     for (int u = 0; u < (int)depth_msg->width; ++u)
     {
       float depth = depth_image_proc::DepthTraits::toMeters(depth_row[u]);
       if (!depth_image_proc::DepthTraits::valid(depth) || depth > max_z_) continue;//不是有效的深度值或者深度超出max_z_
       float y_val = sin_pixel_y[v] * depth;
       float x_val = sin_pixel_x[u] * depth;
       if ( y_val > min_y_ && y_val < max_y_ &&
            x_val > min_x_ && x_val < max_x_)
       {
         x += x_val;
         y += y_val;
         z = std::min(z, depth); //approximate depth as forward.
         n++;
       }
     }
    }
​
    //If there are points, find the centroid and calculate the command goal.
    //If there are no points, simply publish a stop goal.
    //如果有点,找到质心并计算命令目标。如果没有点,只需发布停止消息。
    ROS_INFO_THROTTLE(1, " n ==%d",n);
    if (n>4000)
    {
      x /= n;
      y /= n;
      if(z > max_z_){
        ROS_INFO_THROTTLE(1, "Centroid too far away %f, stopping the robot\n", z);
        if (enabled_)
        {
          cmdpub_.publish(geometry_msgs::TwistPtr(new geometry_msgs::Twist()));
        }
        return;
      }
​
      ROS_INFO_THROTTLE(1, "Centroid at %f %f %f with %d points", x, y, z, n);
      publishMarker(x, y, z);
​
      if (enabled_)
      {
        geometry_msgs::TwistPtr cmd(new geometry_msgs::Twist());
        cmd->linear.x = (z - goal_z_) * z_scale_;
        cmd->angular.z = -x * x_scale_;
        cmdpub_.publish(cmd);
      }
    }
    else
    {
​
      ROS_INFO_THROTTLE(1, "Not enough points(%d) detected, stopping the robot", n);
      publishMarker(x, y, z);
​
      if (enabled_)
      {
​
        cmdpub_.publish(geometry_msgs::TwistPtr(new geometry_msgs::Twist()));
      }
    }
​
    publishBbox();
  }
​
  bool changeModeSrvCb(turtlebot_msgs::SetFollowState::Request& request,
                       turtlebot_msgs::SetFollowState::Response& response)
  {
    if ((enabled_ == true) && (request.state == request.STOPPED))
    {
      ROS_INFO("Change mode service request: following stopped");
      cmdpub_.publish(geometry_msgs::TwistPtr(new geometry_msgs::Twist()));
      enabled_ = false;
    }
    else if ((enabled_ == false) && (request.state == request.FOLLOW))
    {
      ROS_INFO("Change mode service request: following (re)started");
      enabled_ = true;
    }
​
    response.result = response.OK;
    return true;
  }
 //画一个圆点,这个圆点代表质心
  void publishMarker(double x,double y,double z)
  {
    visualization_msgs::Marker marker;
    marker.header.frame_id = "/camera_rgb_optical_frame";
    marker.header.stamp = ros::Time();
    marker.ns = "my_namespace";
    marker.id = 0;
    marker.type = visualization_msgs::Marker::SPHERE;
    marker.action = visualization_msgs::Marker::ADD;
    marker.pose.position.x = x;
    marker.pose.position.y = y;
    marker.pose.position.z = z;
    marker.pose.orientation.x = 0.0;
    marker.pose.orientation.y = 0.0;
    marker.pose.orientation.z = 0.0;
    marker.pose.orientation.w = 1.0;
    marker.scale.x = 0.1;
    marker.scale.y = 0.1;
    marker.scale.z = 0.1;
    marker.color.a = 1.0;
    marker.color.r = 1.0;
    marker.color.g = 0.0;
    marker.color.b = 0.0;
    //only if using a MESH_RESOURCE marker type:
    markerpub_.publish( marker );
  }
 //画一个立方体,这个立方体代表感兴趣区域(RIO)
  void publishBbox()
  {
    double x = (min_x_ + max_x_)/2;
    double y = (min_y_ + max_y_)/2;
    double z = (0 + max_z_)/2;
​
    double scale_x = (max_x_ - x)*2;
    double scale_y = (max_y_ - y)*2;
    double scale_z = (max_z_ - z)*2;
​
    visualization_msgs::Marker marker;
    marker.header.frame_id = "/camera_rgb_optical_frame";
    marker.header.stamp = ros::Time();
    marker.ns = "my_namespace";
    marker.id = 1;
    marker.type = visualization_msgs::Marker::CUBE;
    marker.action = visualization_msgs::Marker::ADD;
    //设置标记物姿态
    marker.pose.position.x = x;
    marker.pose.position.y = -y;
    marker.pose.position.z = z;
    marker.pose.orientation.x = 0.0;
    marker.pose.orientation.y = 0.0;
    marker.pose.orientation.z = 0.0;
    marker.pose.orientation.w = 1.0;
    //设置标记物的尺寸大小
    marker.scale.x = scale_x;
    marker.scale.y = scale_y;
    marker.scale.z = scale_z;
​
    marker.color.a = 0.5;
    marker.color.r = 0.0;
    marker.color.g = 1.0;
    marker.color.b = 0.0;
    //only if using a MESH_RESOURCE marker type:
    bboxpub_.publish( marker );
  }
​
  ros::Subscriber sub_;
  ros::Publisher cmdpub_;
  ros::Publisher markerpub_;
  ros::Publisher bboxpub_;
};
​
PLUGINLIB_DECLARE_CLASS(turtlebot_follower, TurtlebotFollower, turtlebot_follower::TurtlebotFollower, nodelet::Nodelet);
​
}

调试launch文件参数修改

人体跟随效果在转弯处有提升,但较易跟丢



  
   
    
      
      
    
    
    
    
    
    
​
​
   
  
  
  
    
    
​
    
      
      
    
  
  
  
  
     
    
    
    
    
    
​
​
    
    
    
    
    
    
    
    
    
  
  
  
 
  

 

你可能感兴趣的:(机器人,2018暑期)