00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "netft_utils_lean.h"
00018
00019 NetftUtilsLean::NetftUtilsLean(ros::NodeHandle* nh) :
00020 n(nh),
00021 ftAddress(""),
00022 ftTopic(""),
00023 isInit(false),
00024 hasData(false),
00025 cycleRate(0.0),
00026 isFilterOn(false),
00027 deltaTFilter(0.0),
00028 cutoffFrequency(0.0),
00029 newFilter(false),
00030 lpExists(false),
00031 isBiased(false),
00032 isNewBias(false),
00033 waitingForTransform(true),
00034 isActive(false),
00035 cancel_count(MAX_CANCEL),
00036 cancel_wait(MAX_WAIT),
00037 forceMaxB(10.0),
00038 torqueMaxB(0.8),
00039 forceMaxU(50.0),
00040 torqueMaxU(5.0),
00041 toUpdate(false),
00042 toMonitor(false)
00043 {
00044 }
00045
00046 NetftUtilsLean::~NetftUtilsLean()
00047 {
00048 delete listener;
00049 if(lpExists)
00050 delete lp;
00051 }
00052
00053 bool NetftUtilsLean::initialize(double rate, std::string world, std::string ft, double force, double torque)
00054 {
00055
00056 if(!setUserInput(world, ft, force, torque))
00057 {
00058 return false;
00059 }
00060
00061 if(rate>0.001)
00062 {
00063 cycleRate = rate;
00064 }
00065 else
00066 {
00067 ROS_ERROR_STREAM("Cycle rate should positive");
00068 return false;
00069 }
00070
00071
00072 if(!ftTopic.empty())
00073 {
00074 ft_sub = n->subscribe<geometry_msgs::WrenchStamped>(ftTopic, 1, &NetftUtilsLean::dataCallback, this);
00075 ROS_INFO_STREAM("Using NETFT topic instead of IP because ftTopic is:" << ftTopic);
00076 }
00077 else if(!ftAddress.empty())
00078 {
00079 try
00080 {
00081 netft = std::unique_ptr<netft_rdt_driver::NetFTRDTDriver>(new netft_rdt_driver::NetFTRDTDriver(ftAddress));
00082 }
00083 catch(std::runtime_error)
00084 {
00085 ROS_ERROR_STREAM("Could not access data from netft_rdt_driver");
00086 return false;
00087 }
00088 }
00089 else
00090 {
00091 ROS_ERROR_STREAM("Can not initialize FT, must set topic or address first.");
00092 return false;
00093 }
00094
00095
00096
00097 zero_wrench.wrench.force.x = 0.0;
00098 zero_wrench.wrench.force.y = 0.0;
00099 zero_wrench.wrench.force.z = 0.0;
00100 zero_wrench.wrench.torque.x = 0.0;
00101 zero_wrench.wrench.torque.y = 0.0;
00102 zero_wrench.wrench.torque.z = 0.0;
00103
00104
00105 cancel_msg.toCancel = false;
00106
00107
00108 listener = new tf::TransformListener(ros::Duration(300));
00109
00110
00111 netft_cancel_pub = n->advertise<netft_utils::Cancel>("/netft/cancel", 100000);
00112
00113 if(DEBUG_DATA)
00114 data_pub = n->advertise<geometry_msgs::WrenchStamped>("/netft/netft_data", 100000);
00115
00116 isInit = true;
00117 return true;
00118 }
00119
00120 bool NetftUtilsLean::run()
00121 {
00122 if(!isInit)
00123 {
00124 ROS_ERROR_STREAM("Cannot run before initialization is successful.");
00125 return false;
00126 }
00127
00128 isActive = true;
00129
00130 toUpdate = true;
00131 toMonitor = true;
00132
00133
00134 updateThread = std::async(std::launch::async, &NetftUtilsLean::update, this);
00135
00136
00137 if(!ftAddress.empty())
00138 {
00139 monitorThread = std::async(std::launch::async, &NetftUtilsLean::monitorData, this);
00140 }
00141
00142
00143 if(!ftAddress.empty())
00144 {
00145 monitorThread.get();
00146 }
00147 updateThread.get();
00148
00149 isActive = false;
00150 return true;
00151 }
00152
00153 void NetftUtilsLean::stop()
00154 {
00155 toUpdate = false;
00156 toMonitor = false;
00157 }
00158
00159 bool NetftUtilsLean::monitorData()
00160 {
00161 while(waitingForTransform)
00162 {
00163 ros::Duration(0.05).sleep();
00164 }
00165 ros::Rate r(cycleRate);
00166 while (ros::ok() && toMonitor)
00167 {
00168
00169 if (netft->waitForNewData())
00170 {
00171
00172 geometry_msgs::WrenchStamped data;
00173
00174 netft->getData(data);
00175
00176
00177 netftCallback(data);
00178
00179 hasData = true;
00180 }
00181
00182
00183 r.sleep();
00184
00185 }
00186 hasData = false;
00187 return true;
00188 }
00189
00190 void NetftUtilsLean::dataCallback(const geometry_msgs::WrenchStamped::ConstPtr& msg)
00191 {
00192 if(!waitingForTransform && toMonitor)
00193 {
00194 raw_topic_data;
00195 raw_topic_data.header = msg->header;
00196 raw_topic_data.wrench = msg->wrench;
00197 netftCallback(raw_topic_data);
00198 hasData = true;
00199 }
00200 else
00201 hasData = false;
00202 }
00203
00204 bool NetftUtilsLean::isReady()
00205 {
00206 return hasData;
00207 }
00208
00209 bool NetftUtilsLean::waitForData(double timeout)
00210 {
00211 ros::Time startWait = ros::Time::now();
00212 while((ros::Time::now().toSec() - startWait.toSec()) < timeout && !hasData)
00213 {
00214 ros::Duration(0.001).sleep();
00215 }
00216 return hasData;
00217 }
00218
00219 bool NetftUtilsLean::setUserInput(std::string world, std::string ft, double force, double torque)
00220 {
00221 if(world.compare("") == 0)
00222 {
00223 ROS_ERROR_STREAM("World frame string cannot be empty");
00224 return false;
00225 }
00226 world_frame = world;
00227 ROS_INFO_STREAM("World frame: " << world_frame);
00228 if(ft.compare("") == 0)
00229 {
00230 ROS_ERROR_STREAM("FT frame string cannot be empty");
00231 return false;
00232 }
00233 ft_frame = ft;
00234 ROS_INFO_STREAM("FT frame: " << ft_frame);
00235 if(force >= 0.001)
00236 {
00237 forceMaxU = force;
00238 }
00239 else
00240 {
00241 ROS_ERROR_STREAM("FT max force must be positive");
00242 return false;
00243 }
00244 if(torque >= 0.001)
00245 {
00246 torqueMaxU = torque;
00247 }
00248 else
00249 {
00250 ROS_ERROR_STREAM("FT max torque must be positive");
00251 return false;
00252 }
00253 return true;
00254 }
00255
00256 bool NetftUtilsLean::update()
00257 {
00258 if(!isInit)
00259 {
00260 ROS_ERROR_STREAM("Cannot update until NetftUtilsLean is initialized properly.");
00261 return false;
00262 }
00263 ros::Rate r(cycleRate);
00264 while (ros::ok() && toUpdate)
00265 {
00266
00267 if(newFilter)
00268 {
00269 if(lpExists)
00270 delete lp;
00271 lp = new LPFilter(deltaTFilter,cutoffFrequency,6);
00272 lpExists = true;
00273 newFilter = false;
00274 }
00275
00276
00277 tf::StampedTransform tempTransform;
00278 try
00279 {
00280 listener->waitForTransform(world_frame, ft_frame, ros::Time(0), ros::Duration(1.0));
00281 listener->lookupTransform(world_frame, ft_frame, ros::Time(0), tempTransform);
00282 }
00283 catch (tf::TransformException ex)
00284 {
00285 ROS_ERROR("%s",ex.what());
00286 }
00287
00288
00289 tempTransform.setOrigin(tf::Vector3(0.0,0.0,0.0));
00290 ft_to_world = tempTransform;
00291 waitingForTransform = false;
00292
00293 checkMaxForce();
00294
00295
00296 netft_cancel_pub.publish( cancel_msg );
00297 r.sleep();
00298 }
00299 return true;
00300 }
00301
00302 void NetftUtilsLean::copyWrench(geometry_msgs::WrenchStamped &in, geometry_msgs::WrenchStamped &out, geometry_msgs::WrenchStamped &diff)
00303 {
00304 out.header.stamp = in.header.stamp;
00305 out.header.frame_id = in.header.frame_id;
00306 out.wrench.force.x = in.wrench.force.x - diff.wrench.force.x;
00307 out.wrench.force.y = in.wrench.force.y - diff.wrench.force.y;
00308 out.wrench.force.z = in.wrench.force.z - diff.wrench.force.z;
00309 out.wrench.torque.x = in.wrench.torque.x - diff.wrench.torque.x;
00310 out.wrench.torque.y = in.wrench.torque.y - diff.wrench.torque.y;
00311 out.wrench.torque.z = in.wrench.torque.z - diff.wrench.torque.z;
00312 }
00313
00314 void NetftUtilsLean::applyThreshold(double &value, double thresh)
00315 {
00316 if(value <= thresh && value >= -thresh)
00317 {
00318 value = 0.0;
00319 }
00320 }
00321
00322 void NetftUtilsLean::transformFrame(geometry_msgs::WrenchStamped in_data, geometry_msgs::WrenchStamped &out_data, char target_frame)
00323 {
00324 tf::Vector3 tempF;
00325 tf::Vector3 tempT;
00326 tempF.setX(in_data.wrench.force.x);
00327 tempF.setY(in_data.wrench.force.y);
00328 tempF.setZ(in_data.wrench.force.z);
00329 tempT.setX(in_data.wrench.torque.x);
00330 tempT.setY(in_data.wrench.torque.y);
00331 tempT.setZ(in_data.wrench.torque.z);
00332 if(target_frame == 'w')
00333 {
00334 out_data.header.frame_id = world_frame;
00335 tempF = ft_to_world * tempF;
00336 tempT = ft_to_world * tempT;
00337 }
00338 else if(target_frame == 't')
00339 {
00340 out_data.header.frame_id = ft_frame;
00341 tempF = ft_to_world.inverse() * tempF;
00342 tempT = ft_to_world.inverse() * tempT;
00343 }
00344 out_data.header.stamp = in_data.header.stamp;
00345 out_data.wrench.force.x = tempF.getX();
00346 out_data.wrench.force.y = tempF.getY();
00347 out_data.wrench.force.z = tempF.getZ();
00348 out_data.wrench.torque.x = tempT.getX();
00349 out_data.wrench.torque.y = tempT.getY();
00350 out_data.wrench.torque.z = tempT.getZ();
00351 }
00352
00353 void NetftUtilsLean::netftCallback(const geometry_msgs::WrenchStamped& data)
00354 {
00355
00356 std::vector<double> tempData;
00357 tempData.resize(6);
00358 if(!ftAddress.empty())
00359 {
00360 tempData.at(0) = -data.wrench.force.x;
00361 tempData.at(1) = data.wrench.force.y;
00362 tempData.at(2) = data.wrench.force.z;
00363 tempData.at(3) = -data.wrench.torque.x;
00364 tempData.at(4) = data.wrench.torque.y;
00365 tempData.at(5) = data.wrench.torque.z;
00366 }
00367 else
00368 {
00369 tempData.at(0) = data.wrench.force.x;
00370 tempData.at(1) = data.wrench.force.y;
00371 tempData.at(2) = data.wrench.force.z;
00372 tempData.at(3) = data.wrench.torque.x;
00373 tempData.at(4) = data.wrench.torque.y;
00374 tempData.at(5) = data.wrench.torque.z;
00375 }
00376
00377 if(isFilterOn && !newFilter)
00378 lp->update(tempData,tempData);
00379
00380
00381 raw_data_tool.header.stamp = data.header.stamp;
00382 raw_data_tool.header.frame_id = ft_frame;
00383 raw_data_tool.wrench.force.x = tempData.at(0);
00384 raw_data_tool.wrench.force.y = tempData.at(1);
00385 raw_data_tool.wrench.force.z = tempData.at(2);
00386 raw_data_tool.wrench.torque.x = tempData.at(3);
00387 raw_data_tool.wrench.torque.y = tempData.at(4);
00388 raw_data_tool.wrench.torque.z = tempData.at(5);
00389
00390
00391 copyWrench(raw_data_tool, tf_data_tool, bias);
00392
00393
00394 transformFrame(tf_data_tool, tf_data_world, 'w');
00395
00396
00397 applyThreshold(tf_data_world.wrench.force.x, threshold.wrench.force.x);
00398 applyThreshold(tf_data_world.wrench.force.y, threshold.wrench.force.y);
00399 applyThreshold(tf_data_world.wrench.force.z, threshold.wrench.force.z);
00400 applyThreshold(tf_data_world.wrench.torque.x, threshold.wrench.torque.x);
00401 applyThreshold(tf_data_world.wrench.torque.y, threshold.wrench.torque.y);
00402 applyThreshold(tf_data_world.wrench.torque.z, threshold.wrench.torque.z);
00403 applyThreshold(tf_data_tool.wrench.force.x, threshold.wrench.force.x);
00404 applyThreshold(tf_data_tool.wrench.force.y, threshold.wrench.force.y);
00405 applyThreshold(tf_data_tool.wrench.force.z, threshold.wrench.force.z);
00406 applyThreshold(tf_data_tool.wrench.torque.x, threshold.wrench.torque.x);
00407 applyThreshold(tf_data_tool.wrench.torque.y, threshold.wrench.torque.y);
00408 applyThreshold(tf_data_tool.wrench.torque.z, threshold.wrench.torque.z);
00409
00410
00411 if(DEBUG_DATA)
00412 data_pub.publish(tf_data_tool);
00413
00414 }
00415
00416 bool NetftUtilsLean::biasSensor(bool toBias)
00417 {
00418 if(toBias)
00419 {
00420 if(!hasData)
00421 {
00422 geometry_msgs::WrenchStamped data;
00423 if(!ftTopic.empty())
00424 {
00425 ros::Time startTime = ros::Time::now();
00426 while(ros::Time::now().toSec()-startTime.toSec() < 0.1 && !hasData)
00427 {
00428 ros::Duration(0.01).sleep();
00429 }
00430 if(hasData)
00431 {
00432 data = raw_topic_data;
00433 }
00434 else
00435 {
00436 ROS_ERROR("Bias sensor failed.");
00437 return false;
00438 }
00439 }
00440 else
00441 {
00442 if (netft->waitForNewData())
00443 {
00444 netft->getData(data);
00445 }
00446 else
00447 {
00448 ROS_ERROR("Bias sensor failed.");
00449 return false;
00450 }
00451 }
00452
00453 raw_data_tool.header.stamp = data.header.stamp;
00454 raw_data_tool.header.frame_id = ft_frame;
00455 raw_data_tool.wrench.force.x = -data.wrench.force.x;
00456 raw_data_tool.wrench.force.y = data.wrench.force.y;
00457 raw_data_tool.wrench.force.z = data.wrench.force.z;
00458 raw_data_tool.wrench.torque.x = -data.wrench.torque.x;
00459 raw_data_tool.wrench.torque.y = data.wrench.torque.y;
00460 raw_data_tool.wrench.torque.z = data.wrench.torque.z;
00461 }
00462 copyWrench(raw_data_tool, bias, zero_wrench);
00463 isNewBias = true;
00464 }
00465 else
00466 {
00467 copyWrench(zero_wrench, bias, zero_wrench);
00468 }
00469 isBiased = toBias;
00470 return true;
00471 }
00472
00473 bool NetftUtilsLean::setFilter(bool toFilter, double deltaT, double cutoffFreq)
00474 {
00475 if(toFilter)
00476 {
00477 newFilter = true;
00478 isFilterOn = true;
00479 deltaTFilter = deltaT;
00480 cutoffFrequency = cutoffFreq;
00481 }
00482 else
00483 {
00484 isFilterOn = false;
00485 }
00486
00487 return true;
00488 }
00489
00490 bool NetftUtilsLean::setMax(double fMaxU, double tMaxU, double fMaxB, double tMaxB)
00491 {
00492 if(fMaxU >= 0.0001)
00493 {
00494 forceMaxU = fMaxU;
00495 torqueMaxU = tMaxU;
00496 forceMaxB = fMaxB;
00497 torqueMaxB = tMaxB;
00498 return true;
00499 }
00500 else
00501 {
00502 ROS_ERROR_STREAM("All maximum FT values must be positive.");
00503 return false;
00504 }
00505 }
00506
00507 bool NetftUtilsLean::setThreshold(double fThresh, double tThresh)
00508 {
00509 threshold.wrench.force.x = fThresh;
00510 threshold.wrench.force.y = fThresh;
00511 threshold.wrench.force.z = fThresh;
00512 threshold.wrench.torque.x = tThresh;
00513 threshold.wrench.torque.y = tThresh;
00514 threshold.wrench.torque.z = tThresh;
00515
00516 return true;
00517 }
00518
00519 void NetftUtilsLean::checkMaxForce()
00520 {
00521 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);
00522 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);
00523 double fMax;
00524 double tMax;
00525 if(isBiased && !isNewBias)
00526 {
00527 if(forceMaxB > 0.001 && torqueMaxB > 0.001)
00528 {
00529 fMax = forceMaxB;
00530 tMax = torqueMaxB;
00531 }
00532 else
00533 {
00534 fMax = forceMaxU;
00535 tMax = torqueMaxU;
00536 }
00537 }
00538 else
00539 {
00540 if(isBiased && isNewBias)
00541 {
00542 isNewBias = false;
00543 }
00544 fMax = forceMaxU;
00545 tMax = torqueMaxU;
00546 }
00547
00548
00549
00550 if((fabs(fMag) > fMax || fabs(tMag) > tMax) && cancel_count > 0)
00551 {
00552 cancel_msg.toCancel = true;
00553
00554 ROS_INFO("FMAG: %f FMAX: %f TMAG:%f TMAX: %f count: %d wait: %d", fMag, fMax, tMag, tMax, cancel_count, cancel_wait);
00555 cancel_count-=1;
00556 }
00557
00558 else if(cancel_count == 0 && cancel_wait > 0 && cancel_wait <= MAX_WAIT)
00559 {
00560 cancel_msg.toCancel = false;
00561 cancel_wait-=1;
00562 }
00563
00564 else if(cancel_wait == 0 || !(fabs(fMag) > fMax || fabs(tMag) > tMax))
00565 {
00566 cancel_msg.toCancel = false;
00567 cancel_count = MAX_CANCEL;
00568 cancel_wait = MAX_WAIT;
00569 }
00570 }
00571
00572 void NetftUtilsLean::setFTAddress(std::string ftAd)
00573 {
00574 ftAddress = ftAd;
00575 }
00576
00577 void NetftUtilsLean::setFTTopic(std::string ftTop)
00578 {
00579 ftTopic = ftTop;
00580 }
00581
00582 void NetftUtilsLean::getRawData(geometry_msgs::WrenchStamped& data)
00583 {
00584 data = raw_data_tool;
00585 }
00586
00587 void NetftUtilsLean::getToolData(geometry_msgs::WrenchStamped& data)
00588 {
00589 data = tf_data_tool;
00590 }
00591
00592 void NetftUtilsLean::getWorldData(geometry_msgs::WrenchStamped& data)
00593 {
00594 data = tf_data_world;
00595 }
00596
00597 bool NetftUtilsLean::isRunning()
00598 {
00599 return isActive;
00600 }
00601