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
00009 ros::NodeHandle private_nh("~");
00010 private_nh.param<bool>("use_teleop_safety", use_teleop_safety, false);
00011
00012
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
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
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
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
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
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
00124 if (msg->linear.x <= 0.0)
00125 baseCommandPublisher.publish(*msg);
00126 }
00127 else
00128 {
00129
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
00140 if (msg->linear.x <= 0.0)
00141 baseCommandPublisher.publish(*msg);
00142 }
00143 else
00144 {
00145
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
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
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
00275 ros::init(argc, argv, "nav_safety");
00276
00277 NavSafety n;
00278
00279 ros::spin();
00280
00281 return EXIT_SUCCESS;
00282 }