| Line |
Branch |
Exec |
Source |
| 1 |
|
|
/* |
| 2 |
|
|
* Copyright 2010, |
| 3 |
|
|
* François Bleibel, |
| 4 |
|
|
* Olivier Stasse, |
| 5 |
|
|
* |
| 6 |
|
|
* CNRS/AIST |
| 7 |
|
|
* |
| 8 |
|
|
*/ |
| 9 |
|
|
|
| 10 |
|
|
#ifndef __SOT_FEATURE_ABSTRACT_H__ |
| 11 |
|
|
#define __SOT_FEATURE_ABSTRACT_H__ |
| 12 |
|
|
|
| 13 |
|
|
/* --------------------------------------------------------------------- */ |
| 14 |
|
|
/* --- INCLUDE --------------------------------------------------------- */ |
| 15 |
|
|
/* --------------------------------------------------------------------- */ |
| 16 |
|
|
|
| 17 |
|
|
/* Matrix */ |
| 18 |
|
|
#include <dynamic-graph/linear-algebra.h> |
| 19 |
|
|
|
| 20 |
|
|
/* SOT */ |
| 21 |
|
|
#include <dynamic-graph/all-signals.h> |
| 22 |
|
|
#include <dynamic-graph/entity.h> |
| 23 |
|
|
|
| 24 |
|
|
#include <sot/core/flags.hh> |
| 25 |
|
|
#include <sot/core/pool.hh> |
| 26 |
|
|
|
| 27 |
|
|
#include "sot/core/api.hh" |
| 28 |
|
|
|
| 29 |
|
|
/* STD */ |
| 30 |
|
|
#include <string> |
| 31 |
|
|
|
| 32 |
|
|
namespace dynamicgraph { |
| 33 |
|
|
namespace sot { |
| 34 |
|
|
|
| 35 |
|
|
/* --------------------------------------------------------------------- */ |
| 36 |
|
|
/* --- CLASS ----------------------------------------------------------- */ |
| 37 |
|
|
/* --------------------------------------------------------------------- */ |
| 38 |
|
|
|
| 39 |
|
|
/*! \class FeatureAbstract |
| 40 |
|
|
\ingroup features |
| 41 |
|
|
\brief This class gives the abstract definition of a feature. |
| 42 |
|
|
|
| 43 |
|
|
\par par_features_definition Definition |
| 44 |
|
|
In short, a feature is a data evolving according to time. It is defined |
| 45 |
|
|
by a vector \f${\bf s}({\bf q}) \in \mathbb{R}^n \f$ where \f$ {\bf q} \f$ is |
| 46 |
|
|
a robot configuration, which depends on the time \f$ t \f$. By default a |
| 47 |
|
|
feature has a desired \f${\bf s}^*(t) \f$. \f${\bf s}^*\f$ is provided by |
| 48 |
|
|
another feature of the same type called reference. The feature is in charge of |
| 49 |
|
|
collecting its own current state. A feature is supposed to compute an error |
| 50 |
|
|
between its current state and the desired one: \f$ E(t) = e({\bf q}(t), t) = |
| 51 |
|
|
{\bf s}({\bf q}(t)) \ominus {\bf s}^*(t) \f$. Here, \f$ \ominus \f$ is the |
| 52 |
|
|
difference operator of Lie group in which \f$ {\bf s} \f$ and \f$ {\bf s}^* |
| 53 |
|
|
\f$ are. The documentation below assumes the Lie group is a vector space and |
| 54 |
|
|
\f$\ominus\f$ is the usual difference operator. |
| 55 |
|
|
|
| 56 |
|
|
A feature computes: |
| 57 |
|
|
\li the Jacobian according to the robot state vector \f$ J = |
| 58 |
|
|
\frac{\partial e}{\partial {\bf q}} = \frac{\partial{\bf s}}{\partial {\bf |
| 59 |
|
|
q}}\f$. \li the partial derivative of the error \f$ e \f$: \f$ \frac{\partial |
| 60 |
|
|
e}{\partial t} = - \frac{d{\bf s}^*}{dt}\f$. |
| 61 |
|
|
|
| 62 |
|
|
The task is in general computed from the value of the feature at the |
| 63 |
|
|
current instant \f$E(t) = e({\bf q},t)\f$. The derivative of \f$ E \f$ is: |
| 64 |
|
|
\f[ |
| 65 |
|
|
\frac{dE}{dt} = J({\bf q}) \dot{q} + \frac{\partial e}{\partial t} |
| 66 |
|
|
\f] |
| 67 |
|
|
|
| 68 |
|
|
\image html feature.png "Feature diagram: Feature types derive from |
| 69 |
|
|
FeatureAbstract. Each feature has a reference of the same type and |
| 70 |
|
|
compute an error by comparing |
| 71 |
|
|
errorSIN |
| 72 |
|
|
signals from itself and from the |
| 73 |
|
|
reference." |
| 74 |
|
|
|
| 75 |
|
|
*/ |
| 76 |
|
|
class SOT_CORE_EXPORT FeatureAbstract : public Entity { |
| 77 |
|
|
public: |
| 78 |
|
|
/*! \brief Store the name of the class. */ |
| 79 |
|
|
static const std::string CLASS_NAME; |
| 80 |
|
|
|
| 81 |
|
|
/*! \brief Returns the name class. */ |
| 82 |
|
✗ |
virtual const std::string &getClassName(void) const { return CLASS_NAME; } |
| 83 |
|
|
|
| 84 |
|
|
/*! \brief Register the feature in the stack of tasks. */ |
| 85 |
|
|
void featureRegistration(void); |
| 86 |
|
|
|
| 87 |
|
|
void initCommands(void); |
| 88 |
|
|
|
| 89 |
|
|
public: |
| 90 |
|
|
/*! \brief Default constructor: the name of the class should be given. */ |
| 91 |
|
|
FeatureAbstract(const std::string &name); |
| 92 |
|
|
/*! \brief Default destructor */ |
| 93 |
|
16 |
virtual ~FeatureAbstract(void){}; |
| 94 |
|
|
|
| 95 |
|
|
/*! \name Methods returning the dimension of the feature. |
| 96 |
|
|
@{ */ |
| 97 |
|
|
|
| 98 |
|
|
/*! \brief Verbose method. |
| 99 |
|
|
\par res: The integer in which the dimension will be return. |
| 100 |
|
|
\par time: The time at which the feature should be considered. |
| 101 |
|
|
\return Dimension of the feature. |
| 102 |
|
|
\note Be careful with features changing their dimension according to time. |
| 103 |
|
|
*/ |
| 104 |
|
|
virtual unsigned int &getDimension(unsigned int &res, int time) = 0; |
| 105 |
|
|
|
| 106 |
|
|
/*! \brief Short method |
| 107 |
|
|
\par time: The time at which the feature should be considered. |
| 108 |
|
|
\return Dimension of the feature. |
| 109 |
|
|
\note Be careful with features changing their dimension according to time. |
| 110 |
|
|
*/ |
| 111 |
|
|
inline unsigned int getDimension(int time) { |
| 112 |
|
|
unsigned int res; |
| 113 |
|
|
getDimension(res, time); |
| 114 |
|
|
return res; |
| 115 |
|
|
} |
| 116 |
|
|
|
| 117 |
|
|
/*! \brief Shortest method |
| 118 |
|
|
\return Dimension of the feature. |
| 119 |
|
|
\note The feature is not changing its dimension according to time. |
| 120 |
|
|
*/ |
| 121 |
|
|
inline unsigned int getDimension(void) const { |
| 122 |
|
|
return dimensionSOUT.accessCopy(); |
| 123 |
|
|
} |
| 124 |
|
|
/*! @} */ |
| 125 |
|
|
|
| 126 |
|
|
/*! \name Methods to control internal computation. |
| 127 |
|
|
The main idea is that some feature may have a lower frequency |
| 128 |
|
|
than the internal control loop. In this case, the methods for |
| 129 |
|
|
computation are called only when needed. |
| 130 |
|
|
|
| 131 |
|
|
@{*/ |
| 132 |
|
|
|
| 133 |
|
|
/*! \brief Compute the error between the desired feature and |
| 134 |
|
|
the current value of the feature measured or deduced from the robot state. |
| 135 |
|
|
|
| 136 |
|
|
\par[out] res: The error will be set into res. |
| 137 |
|
|
\par[in] time: The time at which the error is computed. |
| 138 |
|
|
\return The vector res with the appropriate value. |
| 139 |
|
|
*/ |
| 140 |
|
|
virtual dynamicgraph::Vector &computeError(dynamicgraph::Vector &res, |
| 141 |
|
|
int time) = 0; |
| 142 |
|
|
|
| 143 |
|
|
/*! \brief Compute the Jacobian of the error according the robot state. |
| 144 |
|
|
|
| 145 |
|
|
\par[out] res: The matrix in which the error will be written. |
| 146 |
|
|
\return The matrix res with the appropriate values. |
| 147 |
|
|
*/ |
| 148 |
|
|
virtual dynamicgraph::Matrix &computeJacobian(dynamicgraph::Matrix &res, |
| 149 |
|
|
int time) = 0; |
| 150 |
|
|
|
| 151 |
|
|
/// Callback for signal errordotSOUT |
| 152 |
|
|
/// |
| 153 |
|
|
/// Copy components of the input signal errordotSIN defined by selection |
| 154 |
|
|
/// flag selectionSIN. |
| 155 |
|
|
virtual dynamicgraph::Vector &computeErrorDot(dynamicgraph::Vector &res, |
| 156 |
|
|
int time); |
| 157 |
|
|
|
| 158 |
|
|
/*! @} */ |
| 159 |
|
|
|
| 160 |
|
|
/* --- SIGNALS ------------------------------------------------------------ */ |
| 161 |
|
|
public: |
| 162 |
|
|
/*! \name Signals |
| 163 |
|
|
@{ |
| 164 |
|
|
*/ |
| 165 |
|
|
|
| 166 |
|
|
/*! \name Input signals: |
| 167 |
|
|
@{ */ |
| 168 |
|
|
/*! \brief This vector specifies which dimension are used to perform the |
| 169 |
|
|
computation. For instance let us assume that the feature is a 3D point. If |
| 170 |
|
|
only the Y-axis should be used for computing error, activation and Jacobian, |
| 171 |
|
|
then the vector to specify |
| 172 |
|
|
is \f$ [ 0 1 0] \f$.*/ |
| 173 |
|
|
SignalPtr<Flags, int> selectionSIN; |
| 174 |
|
|
|
| 175 |
|
|
/// Derivative of the reference value. |
| 176 |
|
|
SignalPtr<dynamicgraph::Vector, int> errordotSIN; |
| 177 |
|
|
|
| 178 |
|
|
/*! @} */ |
| 179 |
|
|
|
| 180 |
|
|
/*! \name Output signals: |
| 181 |
|
|
@{ */ |
| 182 |
|
|
|
| 183 |
|
|
/*! \brief This signal returns the error between the desired value and |
| 184 |
|
|
the current value : \f$ E(t) = {\bf s}(t) - {\bf s}^*(t)\f$ */ |
| 185 |
|
|
SignalTimeDependent<dynamicgraph::Vector, int> errorSOUT; |
| 186 |
|
|
|
| 187 |
|
|
/*! \brief Derivative of the error with respect to time: |
| 188 |
|
|
* \f$ \frac{\partial e}{\partial t} = - \frac{d{\bf s}^*}{dt} \f$ */ |
| 189 |
|
|
SignalTimeDependent<dynamicgraph::Vector, int> errordotSOUT; |
| 190 |
|
|
|
| 191 |
|
|
/*! \brief Jacobian of the error wrt the robot state: |
| 192 |
|
|
* \f$ J = \frac{\partial {\bf s}}{\partial {\bf q}}\f$ */ |
| 193 |
|
|
SignalTimeDependent<dynamicgraph::Matrix, int> jacobianSOUT; |
| 194 |
|
|
|
| 195 |
|
|
/*! \brief Returns the dimension of the feature as an output signal. */ |
| 196 |
|
|
SignalTimeDependent<unsigned int, int> dimensionSOUT; |
| 197 |
|
|
|
| 198 |
|
|
/*! \brief This method write a graph description on the file named |
| 199 |
|
|
FileName. */ |
| 200 |
|
|
virtual std::ostream &writeGraph(std::ostream &os) const; |
| 201 |
|
|
|
| 202 |
|
135 |
virtual SignalTimeDependent<dynamicgraph::Vector, int> &getErrorDot() { |
| 203 |
|
135 |
return errordotSOUT; |
| 204 |
|
|
} |
| 205 |
|
|
|
| 206 |
|
|
/*! @} */ |
| 207 |
|
|
|
| 208 |
|
|
/* --- REFERENCE VALUE S* ------------------------------------------------- */ |
| 209 |
|
|
public: |
| 210 |
|
|
/*! \name Reference |
| 211 |
|
|
@{ |
| 212 |
|
|
*/ |
| 213 |
|
|
virtual void setReference(FeatureAbstract *sdes) = 0; |
| 214 |
|
✗ |
virtual void unsetReference(void) { setReference(NULL); } |
| 215 |
|
|
virtual const FeatureAbstract *getReferenceAbstract(void) const = 0; |
| 216 |
|
|
virtual FeatureAbstract *getReferenceAbstract(void) = 0; |
| 217 |
|
✗ |
virtual bool isReferenceSet(void) const { return false; } |
| 218 |
|
|
|
| 219 |
|
|
virtual void addDependenciesFromReference(void) = 0; |
| 220 |
|
|
virtual void removeDependenciesFromReference(void) = 0; |
| 221 |
|
|
|
| 222 |
|
|
/* Commands for bindings. */ |
| 223 |
|
|
void setReferenceByName(const std::string &name); |
| 224 |
|
|
std::string getReferenceByName(void) const; |
| 225 |
|
|
/*! @} */ |
| 226 |
|
|
}; |
| 227 |
|
|
|
| 228 |
|
|
template <class FeatureSpecialized> |
| 229 |
|
|
class FeatureReferenceHelper { |
| 230 |
|
|
FeatureSpecialized *ptr; |
| 231 |
|
|
FeatureAbstract *ptrA; |
| 232 |
|
|
|
| 233 |
|
|
public: |
| 234 |
|
8 |
FeatureReferenceHelper(void) : ptr(NULL) {} |
| 235 |
|
|
|
| 236 |
|
|
void setReference(FeatureAbstract *sdes); |
| 237 |
|
|
// void setReferenceByName( const std::string & name ); |
| 238 |
|
✗ |
void unsetReference(void) { setReference(NULL); } |
| 239 |
|
36 |
bool isReferenceSet(void) const { return ptr != NULL; } |
| 240 |
|
48 |
FeatureSpecialized *getReference(void) { return ptr; } |
| 241 |
|
✗ |
const FeatureSpecialized *getReference(void) const { return ptr; } |
| 242 |
|
|
}; |
| 243 |
|
|
|
| 244 |
|
|
template <class FeatureSpecialized> |
| 245 |
|
4 |
void FeatureReferenceHelper<FeatureSpecialized>::setReference( |
| 246 |
|
|
FeatureAbstract *sdes) { |
| 247 |
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 |
ptr = dynamic_cast<FeatureSpecialized *>(sdes); |
| 248 |
|
4 |
ptrA = ptr; |
| 249 |
|
4 |
} |
| 250 |
|
|
|
| 251 |
|
|
#define DECLARE_REFERENCE_FUNCTIONS(FeatureSpecialized) \ |
| 252 |
|
|
typedef FeatureReferenceHelper<FeatureSpecialized> SP; \ |
| 253 |
|
|
virtual void setReference(FeatureAbstract *sdes) { \ |
| 254 |
|
|
if (sdes == NULL) { \ |
| 255 |
|
|
/* UNSET */ \ |
| 256 |
|
|
if (SP::isReferenceSet()) removeDependenciesFromReference(); \ |
| 257 |
|
|
SP::unsetReference(); \ |
| 258 |
|
|
} else { \ |
| 259 |
|
|
/* SET */ \ |
| 260 |
|
|
SP::setReference(sdes); \ |
| 261 |
|
|
if (SP::isReferenceSet()) addDependenciesFromReference(); \ |
| 262 |
|
|
} \ |
| 263 |
|
|
} \ |
| 264 |
|
|
virtual const FeatureAbstract *getReferenceAbstract(void) const { \ |
| 265 |
|
|
return SP::getReference(); \ |
| 266 |
|
|
} \ |
| 267 |
|
|
virtual FeatureAbstract *getReferenceAbstract(void) { \ |
| 268 |
|
|
return (FeatureAbstract *)SP::getReference(); \ |
| 269 |
|
|
} \ |
| 270 |
|
|
bool isReferenceSet(void) const { return SP::isReferenceSet(); } \ |
| 271 |
|
|
virtual void addDependenciesFromReference(void); \ |
| 272 |
|
|
virtual void removeDependenciesFromReference(void) |
| 273 |
|
|
/* END OF define DECLARE_REFERENCE_FUNCTIONS */ |
| 274 |
|
|
|
| 275 |
|
|
#define DECLARE_NO_REFERENCE \ |
| 276 |
|
|
virtual void setReference(FeatureAbstract *) {} \ |
| 277 |
|
|
virtual const FeatureAbstract *getReferenceAbstract(void) const { \ |
| 278 |
|
|
return NULL; \ |
| 279 |
|
|
} \ |
| 280 |
|
|
virtual FeatureAbstract *getReferenceAbstract(void) { return NULL; } \ |
| 281 |
|
|
virtual void addDependenciesFromReference(void) {} \ |
| 282 |
|
|
virtual void removeDependenciesFromReference(void) {} \ |
| 283 |
|
|
/* To force a ; */ bool NO_REFERENCE |
| 284 |
|
|
/* END OF define DECLARE_REFERENCE_FUNCTIONS */ |
| 285 |
|
|
|
| 286 |
|
|
} // namespace sot |
| 287 |
|
|
} // namespace dynamicgraph |
| 288 |
|
|
|
| 289 |
|
|
#endif // #ifndef __SOT_FEATURE_ABSTRACT_H__ |
| 290 |
|
|
|