int main(int argc, char **argv)
{
	//initialize the ROS node
	ros::init(argc, argv, "manipulator");
	ros::NodeHandle nh;

	ROS_INFO("Waiting to receive a point cloud to manipulate\n");

	bool pickup_success;
	bool model_fit;
	int model_id;
	Gripper gripper;
    geometry_msgs::Point reset_posn;
	reset_posn.x = 0.6;	reset_posn.y = -0.5; reset_posn.z = 0;
	geometry_msgs::Point red;
	red.x = 0.6;  red.y = -0.5; red.z = -0.1;  //Red bin
	geometry_msgs::Point blue;
	blue.x = 0.6;  blue.y = -0.6; blue.z = -0.1;	//Blue bin
	geometry_msgs::Point green;
	green.x = 0.6; green.y = -0.7; green.z = -0.1;  //Green bin
	geometry_msgs::Point big, medium, small;

	big = red;
	medium = blue;
	small = green;
	
//	const geometry_msgs::Point yellow = {0.45, -0.5, 0};  //Yellow bin
//	const geometry_msgs::Point orange = {0.35, -0.5, 0};  //Orange bin

	int red_color = 0xff0000; 
	const float RGB_RED = *reinterpret_cast<float*>(&red_color);
	int blue_color = 0xff; 
	const float RGB_BLUE = *reinterpret_cast<float*>(&blue_color);
	int green_color = 0xff00; 
	const float RGB_GREEN = *reinterpret_cast<float*>(&green_color);
	
	ros::Subscriber sub = nh.subscribe("pick_place",1,manipulate);
	ros::ServiceClient client_newpcd = 
		nh.serviceClient<duplo_v0::Get_New_PCD>("get_new_pcd");
    duplo_v0::Get_New_PCD srv_newpcd;

	//set service and action names
	const std::string OBJECT_DETECTION_SERVICE_NAME = "/object_detection";
	const std::string COLLISION_PROCESSING_SERVICE_NAME = 
		"/tabletop_collision_map_processing/tabletop_collision_map_processing";
	const std::string PICKUP_ACTION_NAME = 
		"/object_manipulator/object_manipulator_pickup";
	//const std::string PLACE_ACTION_NAME = 
	//	"/object_manipulator/object_manipulator_place";
	const std::string MODEL_FITTING_SERVICE_NAME = 
		"/object_recognition";

	//create service and action clients
	ros::ServiceClient object_detection_srv;
	ros::ServiceClient collision_processing_srv;
	actionlib::SimpleActionClient<object_manipulation_msgs::PickupAction> 
		pickup_client(PICKUP_ACTION_NAME, true);
	//	actionlib::SimpleActionClient<object_manipulation_msgs::PlaceAction> 
	//		place_client(PLACE_ACTION_NAME, true);
	ros::ServiceClient model_fitting_srv;

	//wait for detection client
	while ( !ros::service::waitForService(OBJECT_DETECTION_SERVICE_NAME, 
	                                      ros::Duration(2.0)) && nh.ok() ) 
	{
		ROS_INFO("Waiting for object detection service to come up");
	}
	if (!nh.ok()) exit(0);
	object_detection_srv = 
		nh.serviceClient<tabletop_object_detector::TabletopDetection>
		(OBJECT_DETECTION_SERVICE_NAME, true);

	//wait for collision map processing client
	while ( !ros::service::waitForService(COLLISION_PROCESSING_SERVICE_NAME, 
	                                      ros::Duration(2.0)) && nh.ok() ) 
	{
		ROS_INFO("Waiting for collision processing service to come up");
	}
	if (!nh.ok()) exit(0);
	collision_processing_srv = 
		nh.serviceClient
		<tabletop_collision_map_processing::TabletopCollisionMapProcessing>
		(COLLISION_PROCESSING_SERVICE_NAME, true);

	//wait for pickup client
	while(!pickup_client.waitForServer(ros::Duration(2.0)) && nh.ok())
	{
		ROS_INFO_STREAM("Waiting for action client " << PICKUP_ACTION_NAME);
	}
	if (!nh.ok()) exit(0);  

	//wait for place client
	/*	while(!place_client.waitForServer(ros::Duration(2.0)) && nh.ok())
	{
		ROS_INFO_STREAM("Waiting for action client " << PLACE_ACTION_NAME);
 	}
	if (!nh.ok()) exit(0);    
	*/

	/*while ( !ros::service::waitForService(MODEL_FITTING_SERVICE_NAME, 
	                                      ros::Duration(2.0)) && nh.ok() ) 
	{
		ROS_INFO("Waiting for model fitting service to come up");
	}
	if (!nh.ok()) exit(0);
	model_fitting_srv = nh.serviceClient<tabletop_object_detector::TabletopObjectRecognition>
		(MODEL_FITTING_SERVICE_NAME, true);
*/
	while (ros::ok() && start_manipulation == false) {
		ros::spinOnce();
		if (start_manipulation==true) {
			start_manipulation = false;

			//call the tabletop detection
			ROS_INFO("Calling tabletop detector");
			tabletop_object_detector::TabletopDetection detection_call;
			//we want recognized database objects returned
			//set this to false if you are using the pipeline without the database
			detection_call.request.return_clusters = true;
			//we want the individual object point clouds returned as well
			detection_call.request.return_models = false;
			if (!object_detection_srv.call(detection_call))
			{
				ROS_ERROR("Tabletop detection service failed");
				return false;
			}
			if (detection_call.response.detection.result != 
			    detection_call.response.detection.SUCCESS)
			{
				ROS_ERROR("Tabletop detection returned error code %d", 
				          detection_call.response.detection.result);
				return false;
			}
			if (detection_call.response.detection.clusters.empty() && 
			    detection_call.response.detection.models.empty() )
			{
				ROS_DEBUG("The tabletop detector detected the table, but found no objects");
				//return false;
			}
			detection_call.response.detection.clusters.clear();

			//call collision map processing
			ROS_INFO("Calling collision map processing");
			tabletop_collision_map_processing::TabletopCollisionMapProcessing 
				processing_call;
			//pass the result of the tabletop detection 
			processing_call.request.detection_result = detection_call.response.detection;
			//ask for the exising map and collision models to be reset
			//processing_call.request.reset_static_map = true;
			processing_call.request.reset_collision_models = true;
			processing_call.request.reset_attached_models = true;
			//ask for a new static collision map to be taken with the laser
			//after the new models are added to the environment
			//processing_call.request.take_static_collision_map = false;
			//ask for the results to be returned in base link frame
			processing_call.request.desired_frame = "base_link";
			if (!collision_processing_srv.call(processing_call))
			{
				ROS_ERROR("Collision map processing service failed");
				return false;
			}
			//the collision map processor returns instances of graspable objects
			if (processing_call.response.graspable_objects.empty())
			{
				ROS_DEBUG("Collision map processing returned no graspable objects");
				//return false;
			}

			//call object pickup
			ROS_INFO("Calling the pickup action");
			object_manipulation_msgs::PickupGoal pickup_goal;

			//pass one of the graspable objects returned by the collission map processor

			/*********************************************************************/
			/*********************************************************************/
			/********** Changed *********/
			//pickup_goal.target = processing_call.response.graspable_objects.at(0);

			object_manipulation_msgs::GraspableObject object;
			//object.reference_frame_id = "/openni_rgb_frame";
			sensor_msgs::PointCloud goal_pcd;
			sensor_msgs::PointCloud2 pick_cluster;
			/*toROSMsg(to_pick,pick_cluster);

			tf::TransformListener listener;
			sensor_msgs::PointCloud2 transformed;
			pick_cluster.header.frame_id = "openni_rgb_optical_frame";
			listener.waitForTransform("openni_rgb_optical_frame","base_link",
			                          pick_cluster.header.stamp,ros::Duration(2.0));
			pcl_ros::transformPointCloud("base_link",pick_cluster,transformed,listener);
*/
			if (sensor_msgs::convertPointCloud2ToPointCloud(to_pick,goal_pcd) == true)
			{
				ROS_INFO("Frame Id of input point cloud cluster is: %s\n", goal_pcd.header.frame_id.c_str());
				ROS_INFO("Target frame id is: %s\n", detection_call.response.detection.table.pose.header.frame_id.c_str());
				goal_pcd.header.frame_id = "base_link";
				goal_pcd.header.stamp = ros::Time::now();

				object.cluster = goal_pcd;
				object.reference_frame_id = "base_link";
				pickup_goal.target = object;
				ROS_INFO("Set the goal target as a graspable object\n");

			} else {
				ROS_ERROR("Conversion from pointcloud2 to pointcloud failed.\n");
				return false;
			}

			/**** Fitting a model to goal_pcd ****/
	/*		tabletop_object_detector::TabletopObjectRecognition fitting_call;
			fitting_call.request.clusters.push_back(goal_pcd);
			fitting_call.request.num_models = 1;
			fitting_call.request.perform_fit_merge = false;

			if (!model_fitting_srv.call(fitting_call))
			{
				ROS_ERROR("Model fitting service failed");
				model_fit = false;
				//return false;
			} else {
				model_fit = true;
				model_id = fitting_call.response.cluster_model_indices[0];
			}
*/
			//pass the name that the object has in the collision environment
			//this name was also returned by the collision map processor
			//pickup_goal.collision_object_name = 
			//  processing_call.response.collision_object_names.at(0);
			/*********************************************************************/
			/*********************************************************************/

			//pass the collision name of the table, also returned by the collision 
			//map processor
			pickup_goal.collision_support_surface_name = 
				processing_call.response.collision_support_surface_name;

			/*********************************************************************/
			/*********************************************************************/
			/******* Added: allowing collisions with the table ******/
			pickup_goal.allow_gripper_support_collision = true;
			/*********************************************************************/
			/*********************************************************************/

			//pick up the object with the right arm
			pickup_goal.arm_name = "right_arm";
			//specify the desired distance between pre-grasp and final grasp
			//pickup_goal.desired_approach_distance = 0.1;
			//pickup_goal.min_approach_distance = 0.05;
			//we will be lifting the object along the "vertical" direction
			//which is along the z axis in the base_link frame
			geometry_msgs::Vector3Stamped direction;
			direction.header.stamp = ros::Time::now();
			direction.header.frame_id = "base_link";
			direction.vector.x = 0;
			direction.vector.y = 0;
			direction.vector.z = 1;
			pickup_goal.lift.direction = direction;
			//request a vertical lift of 10cm after grasping the object
			pickup_goal.lift.desired_distance = 0.15;
			pickup_goal.lift.min_distance = 0.1;
			//do not use tactile-based grasping or tactile-based lift
			pickup_goal.use_reactive_lift = false;
			pickup_goal.use_reactive_execution = false;

			//send the goal
			pickup_client.sendGoal(pickup_goal);
			while (!pickup_client.waitForResult(ros::Duration(5.0)))
			{
				ROS_INFO("Waiting for the pickup action...");
			}
			object_manipulation_msgs::PickupResult pickup_result = 
				*(pickup_client.getResult());
			if (pickup_client.getState() != actionlib::SimpleClientGoalState::SUCCEEDED)
			{
				ROS_ERROR("The pickup action has failed with result code %d", 
				          pickup_result.manipulation_result.value);
				pickup_success = false;
				//return false;
			} 
			else 
			{
				ROS_INFO("The pickup action succeeded.");   
				pickup_success= true;
			}
			if (pickup_success) {
				pcl::PointCloud<pcl::PointXYZRGB> temp;
				fromROSMsg(to_pick,temp);
				float longest_dim = find_longest_dim(temp);
				ROS_INFO("PP: Longest dimension of cluster = %f", longest_dim);				   
				if (longest_dim > 0.09) {
					//Place in size A bin
					ROS_INFO("PP: Placing in big bin");
					move_arm(big);
				} else if (longest_dim >= 0.05 && longest_dim <= 0.08) {
					//Place in size B bin
					ROS_INFO("PP: Placing in medium bin");
					move_arm(medium);
				} else if (longest_dim < 0.05) {
					//Place in size C bin
					ROS_INFO("PP: Placing in small bin");
					move_arm(small);
				} else {
					move_arm(reset_posn);
				}
				gripper.open();
			} else {
				move_arm(reset_posn);
			}
			RobotHead head;
			head.lookAt("base_link", 0.2, 0.0, 1.0);
			gripper.open();

			ros::Duration(2).sleep();
			
			// Ask for new PCD
			srv_newpcd.request.question = true;

			if (client_newpcd.call(srv_newpcd)) {
				ROS_INFO("Requesting for new point cloud.");
			} else {
				ROS_ERROR("Failed to call service get new pcd.");
				return 1;
	  		}
		}
		//ros::spin();
	}
	return 0;
}
int main(int argc, char **argv)
{
  //initialize the ROS node
  ros::init(argc, argv, "pick_and_place_app");
  ros::NodeHandle nh;

  //set service and action names
  const std::string OBJECT_DETECTION_SERVICE_NAME = "/object_detection";
  const std::string COLLISION_PROCESSING_SERVICE_NAME = 
    "/tabletop_collision_map_processing/tabletop_collision_map_processing";
  const std::string PICKUP_ACTION_NAME = 
    "/object_manipulator/object_manipulator_pickup";
  const std::string PLACE_ACTION_NAME = 
    "/object_manipulator/object_manipulator_place";

  //create service and action clients
  ros::ServiceClient object_detection_srv;
  ros::ServiceClient collision_processing_srv;
  actionlib::SimpleActionClient<object_manipulation_msgs::PickupAction> 
    pickup_client(PICKUP_ACTION_NAME, true);
  actionlib::SimpleActionClient<object_manipulation_msgs::PlaceAction> 
    place_client(PLACE_ACTION_NAME, true);

  //wait for detection client
  while ( !ros::service::waitForService(OBJECT_DETECTION_SERVICE_NAME, 
                                        ros::Duration(2.0)) && nh.ok() ) 
    {
      ROS_INFO("Waiting for object detection service to come up");
    }
  if (!nh.ok()) exit(0);
  object_detection_srv = 
    nh.serviceClient<tabletop_object_detector::TabletopDetection>
    (OBJECT_DETECTION_SERVICE_NAME, true);

  //wait for collision map processing client
  while ( !ros::service::waitForService(COLLISION_PROCESSING_SERVICE_NAME, 
                                        ros::Duration(2.0)) && nh.ok() ) 
    {
      ROS_INFO("Waiting for collision processing service to come up");
    }
  if (!nh.ok()) exit(0);
  collision_processing_srv = 
    nh.serviceClient
    <tabletop_collision_map_processing::TabletopCollisionMapProcessing>
    (COLLISION_PROCESSING_SERVICE_NAME, true);

  //wait for pickup client
  while(!pickup_client.waitForServer(ros::Duration(2.0)) && nh.ok())
    {
      ROS_INFO_STREAM("Waiting for action client " << PICKUP_ACTION_NAME);
    }
  if (!nh.ok()) exit(0);  

  //wait for place client
  while(!place_client.waitForServer(ros::Duration(2.0)) && nh.ok())
    {
      ROS_INFO_STREAM("Waiting for action client " << PLACE_ACTION_NAME);
    }
  if (!nh.ok()) exit(0);    


  
  //call the tabletop detection
  ROS_INFO("Calling tabletop detector");
  tabletop_object_detector::TabletopDetection detection_call;
  //we want recognized database objects returned
  //set this to false if you are using the pipeline without the database
  detection_call.request.return_clusters = true;
  //we want the individual object point clouds returned as well
  detection_call.request.return_models = true;
  if (!object_detection_srv.call(detection_call))
    {
      ROS_ERROR("Tabletop detection service failed");
      return -1;
    }
  if (detection_call.response.detection.result != 
      detection_call.response.detection.SUCCESS)
    {
      ROS_ERROR("Tabletop detection returned error code %d", 
		detection_call.response.detection.result);
      return -1;
    }
  if (detection_call.response.detection.clusters.empty() && 
      detection_call.response.detection.models.empty() )
    {
      ROS_ERROR("The tabletop detector detected the table, but found no objects");
      return -1;
    }



  //call collision map processing
  ROS_INFO("Calling collision map processing");
  tabletop_collision_map_processing::TabletopCollisionMapProcessing 
    processing_call;
  //pass the result of the tabletop detection 
  processing_call.request.detection_result = detection_call.response.detection;
  //ask for the exising map and collision models to be reset
  processing_call.request.reset_static_map = true;
  processing_call.request.reset_collision_models = true;
  processing_call.request.reset_attached_models = true;
  //ask for a new static collision map to be taken with the laser
  //after the new models are added to the environment
  processing_call.request.take_static_collision_map = true;
  //ask for the results to be returned in base link frame
  processing_call.request.desired_frame = "base_link";
  if (!collision_processing_srv.call(processing_call))
    {
      ROS_ERROR("Collision map processing service failed");
      return -1;
    }
  //the collision map processor returns instances of graspable objects
  if (processing_call.response.graspable_objects.empty())
    {
      ROS_ERROR("Collision map processing returned no graspable objects");
      return -1;
    }


  //call object pickup
  ROS_INFO("Calling the pickup action");
  object_manipulation_msgs::PickupGoal pickup_goal;
  //pass one of the graspable objects returned by the collission map processor
  pickup_goal.target = processing_call.response.graspable_objects.at(0);
  //pass the name that the object has in the collision environment
  //this name was also returned by the collision map processor
  pickup_goal.collision_object_name = 
    processing_call.response.collision_object_names.at(0);
  //pass the collision name of the table, also returned by the collision 
  //map processor
  pickup_goal.collision_support_surface_name = 
    processing_call.response.collision_support_surface_name;
  //pick up the object with the right arm
  pickup_goal.arm_name = "right_arm";
  //specify the desired distance between pre-grasp and final grasp
  pickup_goal.desired_approach_distance = 0.1;
  pickup_goal.min_approach_distance = 0.05;
  //we will be lifting the object along the "vertical" direction
  //which is along the z axis in the base_link frame
  geometry_msgs::Vector3Stamped direction;
  direction.header.stamp = ros::Time::now();
  direction.header.frame_id = "base_link";
  direction.vector.x = 0;
  direction.vector.y = 0;
  direction.vector.z = 1;
  pickup_goal.lift.direction = direction;
  //request a vertical lift of 10cm after grasping the object
  pickup_goal.lift.desired_distance = 0.1;
  pickup_goal.lift.min_distance = 0.05;
  //do not use tactile-based grasping or tactile-based lift
  pickup_goal.use_reactive_lift = false;
  pickup_goal.use_reactive_execution = false;
  //send the goal
  pickup_client.sendGoal(pickup_goal);
  while (!pickup_client.waitForResult(ros::Duration(10.0)))
    {
      ROS_INFO("Waiting for the pickup action...");
    }
  object_manipulation_msgs::PickupResult pickup_result = 
    *(pickup_client.getResult());
  if (pickup_client.getState() != actionlib::SimpleClientGoalState::SUCCEEDED)
    {
      ROS_ERROR("The pickup action has failed with result code %d", 
		pickup_result.manipulation_result.value);
      return -1;
    }


  
  //remember where we picked the object up from
  geometry_msgs::PoseStamped pickup_location;
  if (processing_call.response.graspable_objects.at(0).type == 
      object_manipulation_msgs::GraspableObject::DATABASE_MODEL)
    {
      //for database recognized objects, the location of the object 
      //is encapsulated in GraspableObject the message
    pickup_location = 
      processing_call.response.graspable_objects.at(0).model_pose.pose;
    }
  else
    {
      //for unrecognized point clouds, the location of the object is considered 
      //to be the origin of the frame that the cluster is in
    pickup_location.header = 
      processing_call.response.graspable_objects.at(0).cluster.header;
    //identity pose
    pickup_location.pose.orientation.w = 1;
    }  
  //create a place location, offset by 10 cm from the pickup location
  geometry_msgs::PoseStamped place_location = pickup_location;
  place_location.header.stamp = ros::Time::now();
  place_location.pose.position.x += 0.2;


  //put the object down
  ROS_INFO("Calling the place action");
  object_manipulation_msgs::PlaceGoal place_goal;
  //place at the prepared location
  place_goal.place_pose = place_location;
  //the collision names of both the objects and the table
  //same as in the pickup action
  place_goal.collision_object_name = 
    processing_call.response.collision_object_names.at(0); 
  place_goal.collision_support_surface_name = 
    processing_call.response.collision_support_surface_name;
  //information about which grasp was executed on the object, returned by
  //the pickup action
  place_goal.grasp = pickup_result.grasp;
  //use the right rm to place
  place_goal.arm_name = "right_arm";
  //padding used when determining if the requested place location
  //would bring the object in collision with the environment
  place_goal.place_padding = 0.02;
  //how much the gripper should retreat after placing the object
  place_goal.desired_retreat_distance = 0.40;
  place_goal.min_retreat_distance = 0.20;
  //we will be putting down the object along the "vertical" direction
  //which is along the z axis in the base_link frame
  direction.header.stamp = ros::Time::now();
  direction.header.frame_id = "base_link";
  direction.vector.x = 0;
  direction.vector.y = 0;
  direction.vector.z = -1;
  place_goal.approach.direction = direction;
  //request a vertical put down motion of 10cm before placing the object 
  place_goal.approach.desired_distance = 0.10; //this was 0.1 before, I changed it
  place_goal.approach.min_distance = 0.05;
  //we are not using tactile based placing
  place_goal.use_reactive_place = true;
  //send the goal
  place_client.sendGoal(place_goal);
  while (!place_client.waitForResult(ros::Duration(10.0)))
    {
      ROS_INFO("Waiting for the place action...");
    }
  object_manipulation_msgs::PlaceResult place_result = 
    *(place_client.getResult());
  if (place_client.getState() != actionlib::SimpleClientGoalState::SUCCEEDED)
    {
      ROS_ERROR("Place failed with error code %d", 
		place_result.manipulation_result.value);
      return -1;
    }

  //success!
  ROS_INFO("Success! Object moved.");
  return 0;
}