nav_safety.cpp
Go to the documentation of this file.
00001 #include <carl_safety/nav_safety.h>
00002 
00003 NavSafety::NavSafety() :
00004     acMoveBase("/move_base", true),
00005     acHome("jaco_arm/home_arm", true),
00006     asSafeMove(node, "/move_base_safe", boost::bind(&NavSafety::safeMoveCallback, this, _1), false)
00007 {
00008   // a private handle for this ROS node (allows retrieval of relative parameters)
00009   ros::NodeHandle private_nh("~");
00010   private_nh.param<bool>("use_teleop_safety", use_teleop_safety, false);
00011 
00012   // read in parameters
00013   std::string str;
00014   private_nh.param<std::string>("controller_type", str, "digital");
00015   if (str.compare("digital") == 0)
00016     controllerType = DIGITAL;
00017   else
00018     controllerType = ANALOG;
00019 
00020   // ROS topics
00021   if(use_teleop_safety)
00022     baseCommandPublisher = node.advertise<geometry_msgs::Twist>("cmd_vel_safety_check", 1);
00023   else
00024     baseCommandPublisher = node.advertise<geometry_msgs::Twist>("cmd_vel", 1);
00025   safetyErrorPublisher = node.advertise<carl_safety::Error>("carl_safety/error", 1);
00026 
00027   safeBaseCommandSubscriber = node.subscribe("cmd_vel_safe", 1, &NavSafety::safeBaseCommandCallback, this);
00028   joySubscriber = node.subscribe("joy", 1, &NavSafety::joyCallback, this);
00029   robotPoseSubscriber = node.subscribe("robot_pose", 1, &NavSafety::poseCallback, this);
00030 
00031   // ROS services
00032   jacoPosClient = node.serviceClient<wpi_jaco_msgs::GetAngularPosition>("jaco_arm/get_angular_position");
00033   jacoCartesianClient = node.serviceClient<wpi_jaco_msgs::GetCartesianPosition>("jaco_arm/get_cartesian_position");
00034   stopBaseNavServer = node.advertiseService("carl_safety/stop_base_nav", &NavSafety::navStopCallback, this);
00035 
00036   //initialization
00037   stopped = false;
00038   x = 0.0;
00039   y = 0.0;
00040   theta = 0.0;
00041   retractPos.resize(6);
00042   retractPos[0] = -2.57;
00043   retractPos[1] = 1.39;
00044   retractPos[2] = .527;
00045   retractPos[3] = -.084;
00046   retractPos[4] = .515;
00047   retractPos[5] = -1.745;
00048 
00049   baseFeedbackLastPublished = ros::Time::now();
00050 
00051   asSafeMove.start();
00052 }
00053 
00054 void NavSafety::joyCallback(const sensor_msgs::Joy::ConstPtr& joy)
00055 {
00056   if (controllerType == DIGITAL)
00057   {
00058     if (joy->buttons.at(8) == 1)
00059     {
00060       if (!stopped)
00061       {
00062         stopped = true;
00063         publishStoppedError();
00064       }
00065       cancelNavGoals();
00066     }
00067     else if (joy->buttons.at(9) == 1)
00068     {
00069       if (stopped)
00070       {
00071         stopped = false;
00072         publishClearError();
00073       }
00074     }
00075   }
00076   else
00077   {
00078     if (joy->buttons.at(6) == 1)
00079     {
00080       if (!stopped)
00081       {
00082         stopped = true;
00083         publishStoppedError();
00084       }
00085       cancelNavGoals();
00086     }
00087     else if (joy->buttons.at(7) == 1)
00088     {
00089       if (stopped)
00090       {
00091         stopped = false;
00092         publishClearError();
00093       }
00094     }
00095   }
00096 }
00097 
00098 void NavSafety::safeBaseCommandCallback(const geometry_msgs::Twist::ConstPtr& msg)
00099 {
00100   if (!stopped)
00101   {
00102     if (!isArmContained())
00103     {
00104       //ignore movement command if arm is in a dangerous position
00105       if (ros::Time::now().toSec() - baseFeedbackLastPublished.toSec() > 5.0)
00106       {
00107         publishArmNotContainedError();
00108         baseFeedbackLastPublished = ros::Time::now();
00109       }
00110       return;
00111     }
00112     if (x < BOUNDARY_X && y > BOUNDARY_Y)
00113     {
00114       //pass command through
00115       baseCommandPublisher.publish(*msg);
00116     }
00117     else
00118     {
00119       if (x >= BOUNDARY_X)
00120       {
00121         if (theta > -PI / 2.0 && theta < PI / 2.0)
00122         {
00123           //only publish if going backwards (left on map)
00124           if (msg->linear.x <= 0.0)
00125             baseCommandPublisher.publish(*msg);
00126         }
00127         else
00128         {
00129           //only publish if going forwards (left on map)
00130           if (msg->linear.x >= 0.0)
00131             baseCommandPublisher.publish(*msg);
00132         }
00133       }
00134 
00135       if (y <= BOUNDARY_Y)
00136       {
00137         if (theta > 0.0)
00138         {
00139           //only publish if going forwards (up on map)
00140           if (msg->linear.x <= 0.0)
00141             baseCommandPublisher.publish(*msg);
00142         }
00143         else
00144         {
00145           //only publish if going backwards (up on map)
00146           if (msg->linear.x >= 0.0)
00147             baseCommandPublisher.publish(*msg);
00148         }
00149       }
00150     }
00151   }
00152 }
00153 
00154 void NavSafety::cancelNavGoals()
00155 {
00156   acMoveBase.cancelAllGoals();
00157   move_base_msgs::MoveBaseResult moveResult;
00158   asSafeMove.setAborted(moveResult, "Navigation aborted for safety reasons.");
00159 }
00160 
00161 void NavSafety::poseCallback(const geometry_msgs::Pose::ConstPtr& msg)
00162 {
00163   x = msg->position.x;
00164   y = msg->position.y;
00165 
00166   //convert quaternion to yaw
00167   float q0 = msg->orientation.w;
00168   float q1 = msg->orientation.x;
00169   float q2 = msg->orientation.y;
00170   float q3 = msg->orientation.z;
00171   theta = -atan2(2 * (q0 * q3 + q1 * q2), 1 - 2 * (q2 * q2 + q3 * q3));
00172 }
00173 
00174 void NavSafety::safeMoveCallback(const move_base_msgs::MoveBaseGoalConstPtr &goal)
00175 {
00176   if (!stopped)
00177   {
00178     if (isArmContained())
00179     {
00180       ROS_INFO("Sending nav goal to move_base action server.");
00181       acMoveBase.sendGoal(*goal);
00182       acMoveBase.waitForResult();
00183       asSafeMove.setSucceeded(*acMoveBase.getResult());
00184       ROS_INFO("Navigation finished");
00185     }
00186     else
00187     {
00188       move_base_msgs::MoveBaseResult moveResult;
00189       asSafeMove.setAborted(moveResult, "Navigation aborted because the arm is not contained within the robot's navigation footprint.");
00190       publishArmNotContainedError();
00191     }
00192   }
00193   else
00194   {
00195     move_base_msgs::MoveBaseResult moveResult;
00196     asSafeMove.setAborted(moveResult, "Navigation aborted due to manual safety override.");
00197   }
00198 }
00199 
00200 bool NavSafety::navStopCallback(std_srvs::Empty::Request &req, std_srvs::Empty::Response &res)
00201 {
00202   stopped = true;
00203   cancelNavGoals();
00204 
00205   return true;
00206 }
00207 
00208 bool NavSafety::isArmRetracted()
00209 {
00210   float dstFromRetract = 0;
00211 
00212   //get joint positions
00213   wpi_jaco_msgs::GetAngularPosition::Request req;
00214   wpi_jaco_msgs::GetAngularPosition::Response res;
00215   if(!jacoPosClient.call(req, res))
00216   {
00217     ROS_INFO("Could not call Jaco joint position service.");
00218     return false;
00219   }
00220 
00221   for (unsigned int i = 0; i < 6; i ++)
00222   {
00223     dstFromRetract += fabs(retractPos[i] - res.pos[i]);
00224   }
00225 
00226   if (dstFromRetract > 0.175)
00227     return false;
00228   return true;
00229 }
00230 
00231 bool NavSafety::isArmContained()
00232 {
00233   wpi_jaco_msgs::GetCartesianPosition srv;
00234   if (!jacoCartesianClient.call(srv))
00235   {
00236     ROS_INFO("Could not call Jaco Cartesian position service.");
00237     return false;
00238   }
00239 
00240   return (srv.response.pos.linear.x <= .215 && srv.response.pos.linear.x >= -.435
00241             && fabs(srv.response.pos.linear.y) <= .28
00242             && srv.response.pos.linear.z >= .19);
00243 }
00244 
00245 void NavSafety::publishArmNotContainedError()
00246 {
00247   carl_safety::Error error;
00248   error.message = "Base movement canceled because the arm is not contained.  Please ready or retract the arm before moving.";
00249   error.severity = 0;
00250   error.resolved = false;
00251   safetyErrorPublisher.publish(error);
00252 }
00253 
00254 void NavSafety::publishStoppedError()
00255 {
00256   carl_safety::Error error;
00257   error.message = "Robot control disabled for safety.  Please wait until the robot is re-enabled.";
00258   error.severity = 2;
00259   error.resolved = false;
00260   safetyErrorPublisher.publish(error);
00261 }
00262 
00263 void NavSafety::publishClearError()
00264 {
00265   carl_safety::Error error;
00266   error.message = "Robot re-enabled.";
00267   error.severity = 2;
00268   error.resolved = true;
00269   safetyErrorPublisher.publish(error);
00270 }
00271 
00272 int main(int argc, char **argv)
00273 {
00274   // initialize ROS and the node
00275   ros::init(argc, argv, "nav_safety");
00276 
00277   NavSafety n;
00278 
00279   ros::spin();
00280 
00281   return EXIT_SUCCESS;
00282 }


carl_safety
Author(s): David Kent , Brian Hetherman
autogenerated on Thu Jun 6 2019 19:03:13