robotiq_c_model_action_server.cpp
Go to the documentation of this file.
00001 
00006 #include "robotiq_action_server/robotiq_c_model_action_server.h"
00007 
00008 // To keep the fully qualified names managable
00009 
00010 //Anonymous namespaces are file local -> sort of like global static objects
00011 namespace
00012 {
00013   using namespace robotiq_action_server;
00014 
00015   /*  This struct is declared for the sole purpose of being used as an exception internally
00016       to keep the code clean (i.e. no output params). It is caught by the action_server and 
00017       should not propogate outwards. If you use these functions yourself, beware.
00018   */
00019   struct BadArgumentsError {};
00020 
00021 
00022   GripperOutput goalToRegisterState(const GripperCommandGoal& goal, const CModelGripperParams& params)
00023   {
00024     GripperOutput result;
00025     result.rACT = 0x1; // active gripper
00026     result.rGTO = 0x1; // go to position
00027     result.rATR = 0x0; // No emergency release
00028     result.rSP = 128; // Middle ground speed
00029     
00030     if (goal.command.position > params.max_gap_ || goal.command.position < params.min_gap_)
00031     {
00032       ROS_WARN("Goal gripper gap size is out of range(%f to %f): %f m",
00033                params.min_gap_, params.max_gap_, goal.command.position);
00034       throw BadArgumentsError();
00035     }
00036     
00037     if (goal.command.max_effort < params.min_effort_ || goal.command.max_effort > params.max_effort_)
00038     {
00039       ROS_WARN("Goal gripper effort out of range (%f to %f N): %f N",
00040                params.min_effort_, params.max_effort_, goal.command.max_effort);
00041       throw BadArgumentsError();
00042     }
00043 
00044     double dist_per_tick = (params.max_gap_ - params.min_gap_) / 255;
00045     double eff_per_tick = (params.max_effort_ - params.min_effort_) / 255;
00046 
00047     result.rPR = static_cast<uint8_t>((params.max_gap_ - goal.command.position) / dist_per_tick);
00048     result.rFR = static_cast<uint8_t>((goal.command.max_effort - params.min_effort_) / eff_per_tick);
00049 
00050     ROS_INFO("Setting goal position register to %hhu", result.rPR);
00051 
00052     return result;
00053   }
00054 
00055   /*  This function is templatized because both GripperCommandResult and GripperCommandFeedback consist
00056       of the same fields yet have different types. Templates here act as a "duck typing" mechanism to avoid
00057       code duplication.
00058   */
00059   template<typename T>
00060   T registerStateToResultT(const GripperInput& input, const CModelGripperParams& params, uint8_t goal_pos)
00061   {
00062     T result;
00063     double dist_per_tick = (params.max_gap_ - params.min_gap_) / 255;
00064     double eff_per_tick = (params.max_effort_ - params.min_effort_) / 255;
00065 
00066     result.position = input.gPO * dist_per_tick + params.min_gap_;
00067     result.effort = input.gCU * eff_per_tick + params.min_effort_;
00068     result.stalled = input.gOBJ == 0x1 || input.gOBJ == 0x2;
00069     result.reached_goal = input.gPO == goal_pos;
00070 
00071     return result;
00072   }
00073 
00074   // Inline api-transformers to avoid confusion when reading the action_server source
00075   inline
00076   GripperCommandResult registerStateToResult(const GripperInput& input, const CModelGripperParams& params, uint8_t goal_pos)
00077   {
00078     return registerStateToResultT<GripperCommandResult>(input, params, goal_pos);
00079   }
00080 
00081   inline
00082   GripperCommandFeedback registerStateToFeedback(const GripperInput& input, const CModelGripperParams& params, uint8_t goal_pos)
00083   {
00084     return registerStateToResultT<GripperCommandFeedback>(input, params, goal_pos);
00085   }
00086 
00087 } // end of anon namespace
00088 
00089 namespace robotiq_action_server
00090 {
00091 
00092 CModelGripperActionServer::CModelGripperActionServer(const std::string& name, const CModelGripperParams& params)
00093   : nh_()
00094   , as_(nh_, name, false)
00095   , action_name_(name)
00096   , gripper_params_(params)
00097 {
00098   as_.registerGoalCallback(boost::bind(&CModelGripperActionServer::goalCB, this));
00099   as_.registerPreemptCallback(boost::bind(&CModelGripperActionServer::preemptCB, this));
00100 
00101   state_sub_ = nh_.subscribe("input", 1, &CModelGripperActionServer::analysisCB, this);
00102   goal_pub_ = nh_.advertise<GripperOutput>("output", 1);
00103 
00104   as_.start();
00105 }
00106 
00107 void CModelGripperActionServer::goalCB()
00108 {
00109   // Check to see if the gripper is in an active state where it can take goals
00110   if (current_reg_state_.gSTA != 0x3)
00111   {
00112     ROS_WARN("%s could not accept goal because the gripper is not yet active", action_name_.c_str());
00113     return;
00114   }
00115 
00116   GripperCommandGoal current_goal (*(as_.acceptNewGoal()));
00117 
00118   if (as_.isPreemptRequested())
00119   {
00120     as_.setPreempted();
00121   }
00122 
00123   try
00124   {
00125     goal_reg_state_ = goalToRegisterState(current_goal, gripper_params_);
00126     goal_pub_.publish(goal_reg_state_);
00127   }
00128   catch (BadArgumentsError& e)
00129   {
00130     ROS_INFO("%s No goal issued to gripper", action_name_.c_str());
00131   }
00132 }
00133 
00134 void CModelGripperActionServer::preemptCB()
00135 {
00136   ROS_INFO("%s: Preempted", action_name_.c_str());
00137   as_.setPreempted();
00138 }
00139 
00140 void CModelGripperActionServer::analysisCB(const GripperInput::ConstPtr& msg)
00141 {
00142   current_reg_state_ = *msg;
00143 
00144   if (!as_.isActive()) return;
00145 
00146   // Check to see if the gripper is in its activated state
00147   if (current_reg_state_.gSTA != 0x3)
00148   {
00149     // Check to see if the gripper is active or if it has been asked to be active
00150     if (current_reg_state_.gSTA == 0x0 && goal_reg_state_.rACT != 0x1)
00151     {
00152       // If it hasn't been asked, active it
00153       issueActivation();
00154     }
00155 
00156     // Otherwise wait for the gripper to activate
00157     // TODO: If message delivery isn't guaranteed, then we may want to resend activate
00158     return;
00159   }
00160 
00161   // Check for errors
00162   if (current_reg_state_.gFLT)
00163   {
00164     ROS_WARN("%s faulted with code: %x", action_name_.c_str(), current_reg_state_.gFLT);
00165     as_.setAborted(registerStateToResult(current_reg_state_,
00166                                          gripper_params_,
00167                                          goal_reg_state_.rPR));
00168   }
00169   else if (current_reg_state_.gGTO && current_reg_state_.gOBJ && current_reg_state_.gPR == goal_reg_state_.rPR)
00170   {
00171     // If commanded to move and if at a goal state and if the position request matches the echo'd PR, we're
00172     // done with a move
00173     ROS_INFO("%s succeeded", action_name_.c_str());
00174     as_.setSucceeded(registerStateToResult(current_reg_state_,
00175                                            gripper_params_,
00176                                            goal_reg_state_.rPR));
00177   }
00178   else
00179   {
00180     // Publish feedback
00181     as_.publishFeedback(registerStateToFeedback(current_reg_state_,
00182                                                 gripper_params_,
00183                                                 goal_reg_state_.rPR));
00184   }
00185 }
00186 
00187 void CModelGripperActionServer::issueActivation()
00188 {
00189   ROS_INFO("Activating gripper for gripper action server: %s", action_name_.c_str());
00190   GripperOutput out;
00191   out.rACT = 0x1;
00192   // other params should be zero
00193   goal_reg_state_ = out;
00194   goal_pub_.publish(out);
00195 }
00196 } // end robotiq_action_server namespace


robotiq_action_server
Author(s): Jonathan Meyer
autogenerated on Thu Aug 27 2015 14:44:24