00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "netft_utils.h"
00018
00019 int main(int argc, char **argv)
00020 {
00021
00022 ros::init(argc, argv, "netft_utils_node");
00023
00024
00025 ros::NodeHandle n;
00026 NetftUtils utils(n);
00027 ros::AsyncSpinner spinner(1);
00028 spinner.start();
00029
00030
00031 utils.initialize();
00032
00033
00034 std::string world_frame;
00035 std::string ft_frame;
00036 double forceMaxU = 0.0;
00037 double torqueMaxU = 0.0;
00038 if(argc<3)
00039 {
00040 ROS_FATAL("You must pass in at least the world and ft frame as command line arguments. Argument options are [world frame, ft frame, max force, max torque]");
00041 return 1;
00042 }
00043 else if(argc>=6)
00044 {
00045 ROS_FATAL("Too many arguments for netft_utils");
00046 }
00047 else
00048 {
00049 world_frame = argv[1];
00050 ft_frame = argv[2];
00051 if(argc>=4)
00052 forceMaxU = atof(argv[3]);
00053 if(5==argc)
00054 torqueMaxU = atof(argv[4]);
00055 }
00056 utils.setUserInput(world_frame, ft_frame, forceMaxU, torqueMaxU);
00057
00058
00059 ros::Rate loop_rate(500);
00060
00061 while(ros::ok())
00062 {
00063 utils.update();
00064 loop_rate.sleep();
00065
00066
00067
00068 }
00069
00070 return 0;
00071 }
00072
00073 NetftUtils::NetftUtils(ros::NodeHandle nh) :
00074 n(nh),
00075 isFilterOn(false),
00076 deltaTFilter(0.0),
00077 cutoffFrequency(0.0),
00078 newFilter(false),
00079 isBiased(false),
00080 isGravityBiased(false),
00081 isNewBias(false),
00082 isNewGravityBias(false),
00083 cancel_count(MAX_CANCEL),
00084 cancel_wait(MAX_WAIT),
00085 forceMaxB(10.0),
00086 torqueMaxB(0.8),
00087 forceMaxU(50.0),
00088 torqueMaxU(5.0),
00089 payloadWeight(0.),
00090 payloadLeverArm(0.)
00091 {
00092 }
00093
00094 NetftUtils::~NetftUtils()
00095 {
00096 delete listener;
00097 delete lp;
00098 }
00099
00100 void NetftUtils::initialize()
00101 {
00102
00103
00104
00105 zero_wrench.wrench.force.x = 0.0;
00106 zero_wrench.wrench.force.y = 0.0;
00107 zero_wrench.wrench.force.z = 0.0;
00108 zero_wrench.wrench.torque.x = 0.0;
00109 zero_wrench.wrench.torque.y = 0.0;
00110 zero_wrench.wrench.torque.z = 0.0;
00111
00112
00113 cancel_msg.toCancel = false;
00114
00115
00116 listener = new tf::TransformListener(ros::Duration(300));
00117
00118
00119 raw_data_sub = n.subscribe("netft_data",100, &NetftUtils::netftCallback, this);
00120
00121
00122 netft_raw_world_data_pub = n.advertise<geometry_msgs::WrenchStamped>("raw_world", 100000);
00123 netft_world_data_pub = n.advertise<geometry_msgs::WrenchStamped>("transformed_world", 100000);
00124 netft_tool_data_pub = n.advertise<geometry_msgs::WrenchStamped>("transformed_tool", 100000);
00125 netft_cancel_pub = n.advertise<netft_utils::Cancel>("cancel", 100000);
00126
00127
00128 bias_service = n.advertiseService("bias", &NetftUtils::fixedOrientationBias, this);
00129 gravity_comp_service = n.advertiseService("gravity_comp", &NetftUtils::compensateForGravity, this);
00130 set_max_service = n.advertiseService("set_max_values", &NetftUtils::setMax, this);
00131 theshold_service = n.advertiseService("set_threshold", &NetftUtils::setThreshold, this);
00132 weight_bias_service = n.advertiseService("set_weight_bias", &NetftUtils::setWeightBias, this);
00133 get_weight_service = n.advertiseService("get_weight", &NetftUtils::getWeight, this);
00134 filter_service = n.advertiseService("filter", &NetftUtils::setFilter, this);
00135 }
00136
00137 void NetftUtils::setUserInput(std::string world, std::string ft, double force, double torque)
00138 {
00139 world_frame = world;
00140 ft_frame = ft;
00141 if(force != 0.0)
00142 {
00143 forceMaxU = force;
00144 }
00145 if(torque != 0.0)
00146 {
00147 torqueMaxU = torque;
00148 }
00149 }
00150
00151 void NetftUtils::update()
00152 {
00153
00154 if(newFilter)
00155 {
00156 delete lp;
00157 lp = new LPFilter(deltaTFilter,cutoffFrequency,6);
00158 newFilter = false;
00159 }
00160
00161 tf::StampedTransform tempTransform;
00162 try
00163 {
00164 listener->waitForTransform(world_frame, ft_frame, ros::Time(0), ros::Duration(1.0));
00165 listener->lookupTransform(world_frame, ft_frame, ros::Time(0), tempTransform);
00166 }
00167 catch (tf::TransformException ex)
00168 {
00169 ROS_ERROR("%s",ex.what());
00170 }
00171
00172
00173 tempTransform.setOrigin(tf::Vector3(0.0,0.0,0.0));
00174 ft_to_world = tempTransform;
00175
00176 checkMaxForce();
00177
00178
00179 netft_raw_world_data_pub.publish( raw_data_world );
00180 netft_world_data_pub.publish( tf_data_world );
00181 netft_tool_data_pub.publish( tf_data_tool );
00182 netft_cancel_pub.publish( cancel_msg );
00183
00184 ros::spinOnce();
00185 }
00186
00187 void NetftUtils::copyWrench(geometry_msgs::WrenchStamped &in, geometry_msgs::WrenchStamped &out, geometry_msgs::WrenchStamped &bias)
00188 {
00189 out.header.stamp = in.header.stamp;
00190 out.header.frame_id = in.header.frame_id;
00191 out.wrench.force.x = in.wrench.force.x - bias.wrench.force.x;
00192 out.wrench.force.y = in.wrench.force.y - bias.wrench.force.y;
00193 out.wrench.force.z = in.wrench.force.z - bias.wrench.force.z;
00194 out.wrench.torque.x = in.wrench.torque.x - bias.wrench.torque.x;
00195 out.wrench.torque.y = in.wrench.torque.y - bias.wrench.torque.y;
00196 out.wrench.torque.z = in.wrench.torque.z - bias.wrench.torque.z;
00197 }
00198
00199 void NetftUtils::applyThreshold(double &value, double thresh)
00200 {
00201 if(value <= thresh && value >= -thresh)
00202 {
00203 value = 0.0;
00204 }
00205 }
00206
00207 void NetftUtils::transformFrame(geometry_msgs::WrenchStamped in_data, geometry_msgs::WrenchStamped &out_data, char target_frame)
00208 {
00209 tf::Vector3 tempF;
00210 tf::Vector3 tempT;
00211 tempF.setX(in_data.wrench.force.x);
00212 tempF.setY(in_data.wrench.force.y);
00213 tempF.setZ(in_data.wrench.force.z);
00214 tempT.setX(in_data.wrench.torque.x);
00215 tempT.setY(in_data.wrench.torque.y);
00216 tempT.setZ(in_data.wrench.torque.z);
00217 if(target_frame == 'w')
00218 {
00219 out_data.header.frame_id = world_frame;
00220 tempF = ft_to_world * tempF;
00221 tempT = ft_to_world * tempT;
00222 }
00223 else if(target_frame == 't')
00224 {
00225 out_data.header.frame_id = ft_frame;
00226 tempF = ft_to_world.inverse() * tempF;
00227 tempT = ft_to_world.inverse() * tempT;
00228 }
00229 out_data.header.stamp = in_data.header.stamp;
00230 out_data.wrench.force.x = tempF.getX();
00231 out_data.wrench.force.y = tempF.getY();
00232 out_data.wrench.force.z = tempF.getZ();
00233 out_data.wrench.torque.x = tempT.getX();
00234 out_data.wrench.torque.y = tempT.getY();
00235 out_data.wrench.torque.z = tempT.getZ();
00236 }
00237
00238
00239 void NetftUtils::netftCallback(const geometry_msgs::WrenchStamped::ConstPtr& data)
00240 {
00241
00242 std::vector<double> tempData;
00243 tempData.resize(6);
00244 tempData.at(0) = -data->wrench.force.x;
00245 tempData.at(1) = data->wrench.force.y;
00246 tempData.at(2) = data->wrench.force.z;
00247 tempData.at(3) = -data->wrench.torque.x;
00248 tempData.at(4) = data->wrench.torque.y;
00249 tempData.at(5) = data->wrench.torque.z;
00250
00251 if(isFilterOn && !newFilter)
00252 lp->update(tempData,tempData);
00253
00254
00255 raw_data_tool.header.stamp = data->header.stamp;
00256 raw_data_tool.header.frame_id = ft_frame;
00257 raw_data_tool.wrench.force.x = tempData.at(0);
00258 raw_data_tool.wrench.force.y = tempData.at(1);
00259 raw_data_tool.wrench.force.z = tempData.at(2);
00260 raw_data_tool.wrench.torque.x = tempData.at(3);
00261 raw_data_tool.wrench.torque.y = tempData.at(4);
00262 raw_data_tool.wrench.torque.z = tempData.at(5);
00263
00264
00265 transformFrame(raw_data_tool, raw_data_world, 'w');
00266
00267 if (isGravityBiased)
00268 {
00269
00270
00271 double gravMomentX = -payloadLeverArm*tf_data_tool.wrench.force.y;
00272 double gravMomentY = payloadLeverArm*tf_data_tool.wrench.force.x;
00273
00274
00275 tf_data_tool.wrench.torque.x = tf_data_tool.wrench.torque.x - gravMomentX;
00276 tf_data_tool.wrench.torque.y = tf_data_tool.wrench.torque.y - gravMomentY;
00277
00278
00279
00280 transformFrame(tf_data_tool, tf_data_world, 'w');
00281 tf_data_world.wrench.force.z = tf_data_world.wrench.force.z - payloadWeight;
00282
00283
00284 transformFrame(tf_data_world, tf_data_tool, 't');
00285 }
00286
00287 if (isBiased)
00288 {
00289
00290 geometry_msgs::WrenchStamped world_bias;
00291 transformFrame(bias, world_bias, 'w');
00292
00293 copyWrench(raw_data_world, tf_data_world, world_bias);
00294 }
00295 else
00296 {
00297 copyWrench(raw_data_world, tf_data_world, zero_wrench);
00298 copyWrench(raw_data_tool, tf_data_tool, zero_wrench);
00299 }
00300
00301
00302 applyThreshold(tf_data_world.wrench.force.x, threshold.wrench.force.x);
00303 applyThreshold(tf_data_world.wrench.force.y, threshold.wrench.force.y);
00304 applyThreshold(tf_data_world.wrench.force.z, threshold.wrench.force.z);
00305 applyThreshold(tf_data_world.wrench.torque.x, threshold.wrench.torque.x);
00306 applyThreshold(tf_data_world.wrench.torque.y, threshold.wrench.torque.y);
00307 applyThreshold(tf_data_world.wrench.torque.z, threshold.wrench.torque.z);
00308 applyThreshold(tf_data_tool.wrench.force.x, threshold.wrench.force.x);
00309 applyThreshold(tf_data_tool.wrench.force.y, threshold.wrench.force.y);
00310 applyThreshold(tf_data_tool.wrench.force.z, threshold.wrench.force.z);
00311 applyThreshold(tf_data_tool.wrench.torque.x, threshold.wrench.torque.x);
00312 applyThreshold(tf_data_tool.wrench.torque.y, threshold.wrench.torque.y);
00313 applyThreshold(tf_data_tool.wrench.torque.z, threshold.wrench.torque.z);
00314
00315 }
00316
00317
00318
00319
00320
00321
00322 bool NetftUtils::fixedOrientationBias(netft_utils::SetBias::Request &req, netft_utils::SetBias::Response &res)
00323 {
00324 if(req.toBias)
00325 {
00326 copyWrench(raw_data_tool, bias, zero_wrench);
00327 if(req.forceMax >= 0.0001)
00328 forceMaxB = req.forceMax;
00329 if(req.torqueMax >= 0.0001)
00330 torqueMaxB = req.torqueMax;
00331
00332 isNewBias = true;
00333 isBiased = true;
00334 }
00335 else
00336 {
00337 copyWrench(zero_wrench, bias, zero_wrench);
00338 }
00339
00340 res.success = true;
00341
00342 return true;
00343 }
00344
00345
00346
00347
00348
00349 bool NetftUtils::compensateForGravity(netft_utils::SetBias::Request &req, netft_utils::SetBias::Response &res)
00350 {
00351
00352 if(req.toBias)
00353 {
00354 if (isBiased)
00355 {
00356 ROS_ERROR("Cannot compensate for gravity if the sensor has already been biased, i.e. useful data was wiped out");
00357 res.success = false;
00358 return false;
00359 }
00360 else
00361 {
00362
00363 payloadWeight = raw_data_world.wrench.force.z;
00364
00365
00366
00367
00368 payloadLeverArm = raw_data_tool.wrench.torque.y/raw_data_tool.wrench.force.x;
00369
00370 isNewGravityBias = true;
00371 isGravityBiased = true;
00372 }
00373 }
00374
00375 res.success = true;
00376 return true;
00377 }
00378
00379 bool NetftUtils::setFilter(netft_utils::SetFilter::Request &req, netft_utils::SetFilter::Response &res)
00380 {
00381 if(req.toFilter)
00382 {
00383 newFilter = true;
00384 isFilterOn = true;
00385 deltaTFilter = req.deltaT;
00386 cutoffFrequency = req.cutoffFrequency;
00387 }
00388 else
00389 {
00390 isFilterOn = false;
00391 }
00392
00393 return true;
00394 }
00395
00396 bool NetftUtils::setMax(netft_utils::SetMax::Request &req, netft_utils::SetMax::Response &res)
00397 {
00398 if(req.forceMax >= 0.0001)
00399 forceMaxU = req.forceMax;
00400 if(req.torqueMax >= 0.0001)
00401 torqueMaxU = req.torqueMax;
00402
00403 res.success = true;
00404 return true;
00405 }
00406
00407 bool NetftUtils::setWeightBias(netft_utils::SetBias::Request &req, netft_utils::SetBias::Response &res)
00408 {
00409 if(req.toBias)
00410 {
00411 copyWrench(raw_data_tool, weight_bias, zero_wrench);
00412 }
00413 else
00414 {
00415 copyWrench(zero_wrench, weight_bias, zero_wrench);
00416 }
00417 res.success = true;
00418
00419 return true;
00420 }
00421
00422 bool NetftUtils::getWeight(netft_utils::GetDouble::Request &req, netft_utils::GetDouble::Response &res)
00423 {
00424 geometry_msgs::WrenchStamped carried_weight;
00425 copyWrench(raw_data_tool, carried_weight, weight_bias);
00426 res.weight = pow((pow(carried_weight.wrench.force.x, 2.0) + pow(carried_weight.wrench.force.y, 2.0) + pow(carried_weight.wrench.force.z, 2.0)), 0.5)/9.81*1000;
00427
00428 return true;
00429 }
00430
00431 bool NetftUtils::setThreshold(netft_utils::SetThreshold::Request &req, netft_utils::SetThreshold::Response &res)
00432 {
00433 threshold.wrench.force.x = req.data.wrench.force.x;
00434 threshold.wrench.force.y = req.data.wrench.force.y;
00435 threshold.wrench.force.z = req.data.wrench.force.z;
00436 threshold.wrench.torque.x = req.data.wrench.torque.x;
00437 threshold.wrench.torque.y = req.data.wrench.torque.y;
00438 threshold.wrench.torque.z = req.data.wrench.torque.z;
00439
00440 res.success = true;
00441
00442 return true;
00443 }
00444
00445 void NetftUtils::checkMaxForce()
00446 {
00447 double fMag = pow((pow(tf_data_tool.wrench.force.x, 2.0) + pow(tf_data_tool.wrench.force.y, 2.0) + pow(tf_data_tool.wrench.force.z, 2.0)), 0.5);
00448 double tMag = pow((pow(tf_data_tool.wrench.torque.x, 2.0) + pow(tf_data_tool.wrench.torque.y, 2.0) + pow(tf_data_tool.wrench.torque.z, 2.0)), 0.5);
00449 double fMax;
00450 double tMax;
00451 if(isBiased && !isNewBias)
00452 {
00453 fMax = forceMaxB;
00454 tMax = torqueMaxB;
00455 }
00456 else
00457 {
00458 if(isBiased && isNewBias)
00459 {
00460 isNewBias = false;
00461 }
00462
00463 fMax = forceMaxU;
00464 tMax = torqueMaxU;
00465 }
00466
00467
00468
00469 if((fabs(fMag) > fMax || fabs(tMag) > tMax) && cancel_count > 0)
00470 {
00471 cancel_msg.toCancel = true;
00472
00473 ROS_INFO("FMAG: %f FMAX: %f TMAG:%f TMAX: %f count: %d wait: %d", fMag, fMax, tMag, tMax, cancel_count, cancel_wait);
00474 cancel_count-=1;
00475 }
00476
00477 else if(cancel_count == 0 && cancel_wait > 0 && cancel_wait <= MAX_WAIT)
00478 {
00479 cancel_msg.toCancel = false;
00480 cancel_wait-=1;
00481 }
00482
00483 else if(cancel_wait == 0 || !(fabs(fMag) > fMax || fabs(tMag) > tMax))
00484 {
00485 cancel_msg.toCancel = false;
00486 cancel_count = MAX_CANCEL;
00487 cancel_wait = MAX_WAIT;
00488 }
00489 }
00490