Libbarrett  1.2.4
include/barrett/systems/detail/wam-inl.h
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Defines