Libbarrett
1.2.4
|
00001 /* 00002 Copyright 2009, 2010, 2011, 2012 Barrett Technology <support@barrett.com> 00003 00004 This file is part of libbarrett. 00005 00006 This version of libbarrett is free software: you can redistribute it 00007 and/or modify it under the terms of the GNU General Public License as 00008 published by the Free Software Foundation, either version 3 of the 00009 License, or (at your option) any later version. 00010 00011 This version of libbarrett is distributed in the hope that it will be 00012 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License along 00017 with this version of libbarrett. If not, see 00018 <http://www.gnu.org/licenses/>. 00019 00020 Further, non-binding information about licensing is available at: 00021 <http://wiki.barrett.com/libbarrett/wiki/LicenseNotes> 00022 */ 00023 00024 /* 00025 * wam-inl.h 00026 * 00027 * Created on: Sep 25, 2009 00028 * Author: dc 00029 */ 00030 00031 00032 #include <unistd.h> // usleep 00033 00034 #include <boost/ref.hpp> 00035 #include <boost/bind.hpp> 00036 #include <boost/thread.hpp> 00037 00038 #define EIGEN_USE_NEW_STDVECTOR 00039 #include <Eigen/StdVector> 00040 #include <Eigen/Core> 00041 #include <Eigen/Geometry> 00042 00043 #include <libconfig.h> 00044 00045 #include <barrett/os.h> 00046 #include <barrett/units.h> 00047 #include <barrett/products/puck.h> 00048 #include <barrett/products/safety_module.h> 00049 #include <barrett/thread/abstract/mutex.h> 00050 #include <barrett/math/spline.h> 00051 #include <barrett/math/trapezoidal_velocity_profile.h> 00052 #include <barrett/systems/abstract/system.h> 00053 #include <barrett/systems/io_conversion.h> 00054 #include <barrett/systems/ramp.h> 00055 #include <barrett/systems/callback.h> 00056 00057 00058 namespace barrett { 00059 namespace systems { 00060 00061 00062 // TODO(dc): some of these members should be inline 00063 00064 template<size_t DOF> 00065 Wam<DOF>::Wam(ExecutionManager* em, const std::vector<Puck*>& genericPucks, 00066 SafetyModule* safetyModule, const libconfig::Setting& setting, 00067 std::vector<int> torqueGroupIds, const std::string& sysName) : 00068 llww(em, genericPucks, safetyModule, setting["low_level"], torqueGroupIds, sysName + "::LowLevel"), 00069 kinematicsBase(setting["kinematics"]), 00070 gravity(setting["gravity_compensation"]), 00071 jvFilter(setting["joint_velocity_filter"]), 00072 toolPosition(), 00073 toolVelocity(), 00074 toolOrientation(), 00075 toolPose(), 00076 00077 supervisoryController(), 00078 jtPassthrough(1.0), 00079 jpController(setting["joint_position_control"]), 00080 jvController1(setting["joint_velocity_control"][0]), 00081 jvController2(setting["joint_velocity_control"][1]), 00082 tpController(setting["tool_position_control"]), 00083 tf2jt(), 00084 toController(setting["tool_orientation_control"]), 00085 tt2jt(), 00086 00087 tpoSplitter(), 00088 tpoTpController(setting["tool_position_control"]), 00089 tpoTf2jt(), 00090 tpoToController(setting["tool_orientation_control"]), 00091 tpoTt2jt(), 00092 tpoSum(), 00093 00094 jtSum(true), 00095 00096 input(jtSum.getInput(JT_INPUT)), jpOutput(llww.jpOutput), jvOutput(jvFilter.output), 00097 00098 doneMoving(true), 00099 kin(setting["kinematics"]) 00100 { 00101 connect(llww.jpOutput, kinematicsBase.jpInput); 00102 connect(jvOutput, kinematicsBase.jvInput); 00103 00104 connect(kinematicsBase.kinOutput, gravity.kinInput); 00105 // Don't connect gravity.output here. Gravity compensation is off by default. 00106 00107 connect(kinematicsBase.kinOutput, toolPosition.kinInput); 00108 connect(kinematicsBase.kinOutput, toolVelocity.kinInput); 00109 connect(kinematicsBase.kinOutput, toolOrientation.kinInput); 00110 connect(kinematicsBase.kinOutput, tf2jt.kinInput); 00111 connect(kinematicsBase.kinOutput, toController.kinInput); 00112 connect(kinematicsBase.kinOutput, tt2jt.kinInput); 00113 connect(kinematicsBase.kinOutput, tpoTf2jt.kinInput); 00114 connect(kinematicsBase.kinOutput, tpoToController.kinInput); 00115 connect(kinematicsBase.kinOutput, tpoTt2jt.kinInput); 00116 00117 connect(toolPosition.output, toolPose.getInput<0>()); 00118 connect(toolOrientation.output, toolPose.getInput<1>()); 00119 00120 connect(llww.jvOutput, jvFilter.input); 00121 if (em != NULL) { 00122 // Keep the jvFilter updated so it will provide accurate values for 00123 // calls to Wam::getJointVelocities(). 00124 em->startManaging(jvFilter); 00125 } 00126 00127 supervisoryController.registerConversion(makeIOConversion( 00128 jtPassthrough.input, jtPassthrough.output)); 00129 00130 connect(llww.jpOutput, jpController.feedbackInput); 00131 supervisoryController.registerConversion(makeIOConversion( 00132 jpController.referenceInput, jpController.controlOutput)); 00133 00134 // TODO(dc): combine into single controller 00135 connect(jvOutput, jvController1.feedbackInput); 00136 connect(jvController1.controlOutput, jvController2.input); 00137 supervisoryController.registerConversion(makeIOConversion( 00138 jvController1.referenceInput, jvController2.output)); 00139 00140 connect(toolPosition.output, tpController.feedbackInput); 00141 connect(tpController.controlOutput, tf2jt.input); 00142 supervisoryController.registerConversion(makeIOConversion( 00143 tpController.referenceInput, tf2jt.output)); 00144 00145 connect(toolOrientation.output, toController.feedbackInput); 00146 connect(toController.controlOutput, tt2jt.input); 00147 supervisoryController.registerConversion(makeIOConversion( 00148 toController.referenceInput, tt2jt.output)); 00149 00150 connect(tpoSplitter.getOutput<0>(), tpoTpController.referenceInput); 00151 connect(toolPosition.output, tpoTpController.feedbackInput); 00152 connect(tpoTpController.controlOutput, tpoTf2jt.input); 00153 connect(tpoTf2jt.output, tpoSum.getInput(0)); 00154 00155 connect(tpoSplitter.getOutput<1>(), tpoToController.referenceInput); 00156 connect(toolOrientation.output, tpoToController.feedbackInput); 00157 connect(tpoToController.controlOutput, tpoTt2jt.input); 00158 connect(tpoTt2jt.output, tpoSum.getInput(1)); 00159 supervisoryController.registerConversion(makeIOConversion( 00160 tpoSplitter.input, tpoSum.output)); 00161 00162 connect(supervisoryController.output, jtSum.getInput(SC_INPUT)); 00163 connect(jtSum.output, llww.input); 00164 } 00165 00166 template<size_t DOF> 00167 Wam<DOF>::~Wam() 00168 { 00169 // Make sure any outstanding moveTo() threads are cleaned up 00170 mtThreadGroup.interrupt_all(); 00171 mtThreadGroup.join_all(); 00172 } 00173 00174 template<size_t DOF> 00175 template<typename T> 00176 void Wam<DOF>::trackReferenceSignal(System::Output<T>& referenceSignal) 00177 { 00178 supervisoryController.connectInputTo(referenceSignal); 00179 } 00180 00181 template<size_t DOF> 00182 inline const typename Wam<DOF>::jp_type& Wam<DOF>::getHomePosition() const 00183 { 00184 return getLowLevelWam().getHomePosition(); 00185 } 00186 00187 template<size_t DOF> 00188 typename Wam<DOF>::jt_type Wam<DOF>::getJointTorques() const 00189 { 00190 { 00191 BARRETT_SCOPED_LOCK(getEmMutex()); 00192 if (llww.input.valueDefined()) { 00193 return llww.input.getValue(); 00194 } 00195 } 00196 00197 return jt_type(); 00198 } 00199 00200 template<size_t DOF> 00201 inline typename Wam<DOF>::jp_type Wam<DOF>::getJointPositions() const 00202 { 00203 return getLowLevelWam().getJointPositions(); 00204 } 00205 00206 template<size_t DOF> 00207 inline typename Wam<DOF>::jv_type Wam<DOF>::getJointVelocities() const 00208 { 00209 { 00210 BARRETT_SCOPED_LOCK(getEmMutex()); 00211 00212 // Return the filtered velocity, if available. 00213 if (jvController1.feedbackInput.valueDefined()) { 00214 return jvController1.feedbackInput.getValue(); 00215 } 00216 } 00217 00218 // Otherwise just return differentiated positions. 00219 return getLowLevelWam().getJointVelocities(); 00220 } 00221 00222 template<size_t DOF> 00223 typename Wam<DOF>::cp_type Wam<DOF>::getToolPosition() const 00224 { 00225 { 00226 BARRETT_SCOPED_LOCK(getEmMutex()); 00227 if (tpController.feedbackInput.valueDefined()) { 00228 return tpController.feedbackInput.getValue(); 00229 } 00230 } 00231 00232 kin.eval(getJointPositions(), getJointVelocities()); 00233 return cp_type(kin.impl->tool->origin_pos); 00234 } 00235 00236 template<size_t DOF> 00237 typename Wam<DOF>::cv_type Wam<DOF>::getToolVelocity() const 00238 { 00239 kin.eval(getJointPositions(), getJointVelocities()); 00240 return cv_type(kin.impl->tool_velocity); 00241 } 00242 00243 template<size_t DOF> 00244 Eigen::Quaterniond Wam<DOF>::getToolOrientation() const 00245 { 00246 { 00247 BARRETT_SCOPED_LOCK(getEmMutex()); 00248 if (toController.feedbackInput.valueDefined()) { 00249 return toController.feedbackInput.getValue(); 00250 } 00251 } 00252 00253 kin.eval(getJointPositions(), getJointVelocities()); 00254 math::Matrix<3,3> rot(kin.impl->tool->rot_to_world); 00255 return Eigen::Quaterniond(rot.transpose()); 00256 } 00257 00258 template<size_t DOF> 00259 inline typename Wam<DOF>::pose_type Wam<DOF>::getToolPose() const 00260 { 00261 return boost::make_tuple(getToolPosition(), getToolOrientation()); 00262 } 00263 00264 template<size_t DOF> 00265 inline math::Matrix<6,DOF> Wam<DOF>::getToolJacobian() const 00266 { 00267 kin.eval(getJointPositions(), getJointVelocities()); 00268 return math::Matrix<6,DOF>(kin.impl->tool_jacobian); 00269 } 00270 00271 template<size_t DOF> 00272 void Wam<DOF>::gravityCompensate(bool compensate) 00273 { 00274 if (compensate) { 00275 forceConnect(gravity.output, jtSum.getInput(GRAVITY_INPUT)); 00276 } else { 00277 disconnect(jtSum.getInput(GRAVITY_INPUT)); 00278 } 00279 } 00280 00281 template<size_t DOF> 00282 bool Wam<DOF>::updateGravity(double val) 00283 { 00284 return (gravity.setGravity(val)); 00285 } 00286 00287 template<size_t DOF> 00288 inline bool Wam<DOF>::isGravityCompensated() 00289 { 00290 return jtSum.getInput(GRAVITY_INPUT).isConnected(); 00291 } 00292 00293 template<size_t DOF> 00294 inline void Wam<DOF>::moveHome(bool blocking) 00295 { 00296 moveTo(getHomePosition(), blocking); 00297 } 00298 template<size_t DOF> 00299 inline void Wam<DOF>::moveHome(bool blocking, double velocity) 00300 { 00301 moveTo(getHomePosition(), blocking, velocity); 00302 } 00303 template<size_t DOF> 00304 inline void Wam<DOF>::moveHome(bool blocking, double velocity, double acceleration) 00305 { 00306 moveTo(getHomePosition(), blocking, velocity, acceleration); 00307 } 00308 00309 template<size_t DOF> 00310 inline void Wam<DOF>::moveTo(const jp_type& destination, bool blocking, double velocity, double acceleration) 00311 { 00312 // moveTo(currentPosHelper(getJointPositions()), getJointVelocities(), destination, blocking, velocity, acceleration); 00313 moveTo(currentPosHelper(getJointPositions()), /*jv_type(0.0),*/ destination, blocking, velocity, acceleration); 00314 } 00315 00316 template<size_t DOF> 00317 inline void Wam<DOF>::moveTo(const cp_type& destination, bool blocking, double velocity, double acceleration) 00318 { 00319 moveTo(currentPosHelper(getToolPosition()), /*cv_type(0.0),*/ destination, blocking, velocity, acceleration); 00320 } 00321 00322 template<size_t DOF> 00323 inline void Wam<DOF>::moveTo(const Eigen::Quaterniond& destination, bool blocking, double velocity, double acceleration) 00324 { 00325 moveTo(currentPosHelper(getToolOrientation()), destination, blocking, velocity, acceleration); 00326 } 00327 00328 template<size_t DOF> 00329 inline void Wam<DOF>::moveTo(const pose_type& destination, bool blocking, double velocity, double acceleration) 00330 { 00331 moveTo(currentPosHelper(getToolPose()), destination, blocking, velocity, acceleration); 00332 } 00333 00334 template<size_t DOF> 00335 template<typename T> 00336 void Wam<DOF>::moveTo(const T& currentPos, /*const typename T::unitless_type& currentVel,*/ const T& destination, bool blocking, double velocity, double acceleration) 00337 { 00338 bool started = false; 00339 boost::promise<boost::thread*> threadPtrPromise; 00340 boost::shared_future<boost::thread*> threadPtrFuture(threadPtrPromise.get_future()); 00341 boost::thread* threadPtr = new boost::thread(&Wam<DOF>::moveToThread<T>, this, boost::ref(currentPos), /*currentVel,*/ boost::ref(destination), velocity, acceleration, &started, threadPtrFuture); 00342 mtThreadGroup.add_thread(threadPtr); 00343 threadPtrPromise.set_value(threadPtr); 00344 00345 00346 // wait until move starts 00347 while ( !started ) { 00348 btsleep(0.001); 00349 } 00350 00351 if (blocking) { 00352 while (!moveIsDone()) { 00353 btsleep(0.01); 00354 } 00355 } 00356 } 00357 00358 template<size_t DOF> 00359 bool Wam<DOF>::moveIsDone() const 00360 { 00361 return doneMoving; 00362 } 00363 00364 template<size_t DOF> 00365 void Wam<DOF>::idle() 00366 { 00367 supervisoryController.disconnectInput(); 00368 } 00369 00370 00371 template<size_t DOF> 00372 template<typename T> 00373 T Wam<DOF>::currentPosHelper(const T& currentPos) 00374 { 00375 System::Input<T>* input = NULL; 00376 supervisoryController.getInput(&input); 00377 if (input != NULL && input->valueDefined()) { 00378 // If we're already using the controller we're about to use in the 00379 // moveTo() call, it's best to treat the current *set point* as the 00380 // "current position". That way the reference signal is continuous as it 00381 // transitions from whatever is happening now to the moveTo() Spline. 00382 return input->getValue(); 00383 } 00384 00385 // If we're not using the appropriate controller already, then use our 00386 // *actual* current position. 00387 return currentPos; 00388 } 00389 00390 template<size_t DOF> 00391 template<typename T> 00392 void Wam<DOF>::moveToThread(const T& currentPos, /*const typename T::unitless_type& currentVel,*/ const T& destination, double velocity, double acceleration, bool* started, boost::shared_future<boost::thread*> threadPtrFuture) 00393 { 00394 // Only remove this thread from mtThreadGroup on orderly exit. (Don't remove on exception.) 00395 bool removeThread = false; 00396 00397 try { 00398 std::vector<T, Eigen::aligned_allocator<T> > vec; 00399 vec.push_back(currentPos); 00400 vec.push_back(destination); 00401 00402 // TODO(dc): Use currentVel. Requires changes to math::spline<Eigen::Quaternion<T> > specialization. 00403 //math::Spline<T> spline(vec, currentVel); 00404 //math::TrapezoidalVelocityProfile profile(velocity, acceleration, currentVel.norm(), spline.changeInS()); 00405 math::Spline<T> spline(vec); 00406 math::TrapezoidalVelocityProfile profile(velocity, acceleration, 0.0, spline.changeInS()); 00407 00408 Ramp time(NULL, 1.0); 00409 Callback<double, T> trajectory(boost::bind(boost::ref(spline), boost::bind(boost::ref(profile), _1))); 00410 00411 connect(time.output, trajectory.input); 00412 trackReferenceSignal(trajectory.output); 00413 time.start(); 00414 00415 doneMoving = false; 00416 *started = true; 00417 00418 // The value of trajectory.input will be undefined until the next execution cycle. 00419 // It may become undefined again if trajectory.output is disconnected and this chain 00420 // of Systems loses its ExecutionManager. We must check that the value is defined 00421 // before calling getValue(). 00422 while ( !trajectory.input.valueDefined() || trajectory.input.getValue() < profile.finalT()) { 00423 // if the move is interrupted, clean up and end the thread 00424 if ( !trajectory.output.isConnected() || boost::this_thread::interruption_requested() ) { 00425 removeThread = true; 00426 break; 00427 } 00428 btsleep(0.01); // Interruption point. May throw boost::thread_interrupted 00429 } 00430 00431 if ( !removeThread ) { 00432 doneMoving = true; 00433 00434 // Wait until the trajectory is no longer referenced by supervisoryController 00435 while (trajectory.hasExecutionManager() && !boost::this_thread::interruption_requested()) { 00436 btsleep(0.01); // Interruption point. May throw boost::thread_interrupted 00437 } 00438 removeThread = true; 00439 } 00440 } catch (const boost::thread_interrupted& e) {} 00441 00442 if (removeThread) { 00443 mtThreadGroup.remove_thread(threadPtrFuture.get()); 00444 delete threadPtrFuture.get(); 00445 } 00446 } 00447 00448 00449 } 00450 }