00001 #ifndef TUBE_TARE_UTILITIES_H
00002 #define TUBE_TARE_UTILITIES_H
00003
00004 #include <boost/array.hpp>
00005 #include "robodyn_mechanisms/TubeTareInterface.h"
00006 #include "robot_instance/StringUtilities.h"
00007 #include "robodyn_mechanisms/FingerController.h"
00008
00009 template<unsigned int N>
00010 class TubeTareMechanism : public TubeTareInterface
00011 {
00012 public:
00013 TubeTareMechanism(const std::string& mechanism, TubeTareInterface::IoFunctions ioFunctions, float freq);
00014 virtual ~TubeTareMechanism();
00015
00016 virtual void setStop(const std::vector<std::string>& actuators = std::vector<std::string>());
00017 virtual bool isMoving();
00018 virtual void setRelease(const std::vector<std::string>& actuators = std::vector<std::string>());
00019 virtual void getEncoderTarePos();
00020 virtual void setTighten(const std::vector<std::string>& actuators = std::vector<std::string>());
00021 virtual int goodPosition();
00022 virtual void getSliderTarePos();
00023 virtual void getTensionTareValue();
00024 virtual void resetTensionCounter();
00025
00026 FingerController<N> finger;
00027 typedef typename FingerController<N>::SliderVectorType SliderVectorType;
00028 typedef typename FingerController<N>::ReferenceMatrixType ReferenceMatrixType;
00029 typedef typename FingerController<N>::JointVectorType hallVec;
00030
00031 private:
00032
00033
00034
00035
00036
00037
00038 boost::array<std::string, N> hallStateElements;
00039 boost::array < std::string, N + 1 > encoderStateElements;
00040 boost::array < std::string, N + 1 > tensionAStateElements;
00041 boost::array < std::string, N + 1 > tensionBStateElements;
00042 boost::array < std::string, N + 1 > motComCommandElements;
00043
00044 float encoderVelZeroThreshold, encoderMinTravel, encoderMaxTravel;
00045
00046 SliderVectorType motComReleaseVal, motComTightenVal;
00047 SliderVectorType tensionGainA, tensionGainB, tensionSensorCalOffset, tension_out;
00048
00049 boost::array < std::string, N + 1 > encoderOffsetElements;
00050 boost::array < std::string, N + 1 > sliderOffsetElements;
00051 boost::array < std::string, N + 1 > sliderTarePosElements;
00052 boost::array < std::string, N + 1 > tensionOffsetElements;
00053
00054
00055 typename FingerController<N>::SliderVectorType encoderVec;
00056 typename FingerController<N>::SliderVectorType filteredEncoderVec;
00057 typename FingerController<N>::SliderVectorType encoderVels;
00058 typename FingerController<N>::SliderVectorType prevEncoderVec;
00059 double timestep;
00060 double positionAlpha;
00061 bool filterInitialized;
00062
00063 unsigned int tensionCounter;
00064
00065 void setParameters();
00066
00067 };
00068
00069 template <unsigned int N>
00070 TubeTareMechanism<N>::TubeTareMechanism(const std::string& mechanism, TubeTareInterface::IoFunctions ioFunctions, float freq)
00071 : TubeTareInterface(mechanism, ioFunctions), filterInitialized(false)
00072 {
00073 if (mechanism == "")
00074 {
00075 std::stringstream err;
00076 err << "Constructor requires mechanism be non-empty.";
00077 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::FATAL, err.str());
00078 throw std::invalid_argument(err.str());
00079 }
00080
00081 if (freq <= 0.)
00082 {
00083 std::stringstream err;
00084 err << "frequency must be positive";
00085 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::FATAL, err.str());
00086 throw std::invalid_argument(err.str());
00087 }
00088
00089 if (io.getUInt16.empty() or
00090 io.getInt16.empty() or
00091 io.setInt16.empty() or
00092 io.getMotorCoeff.empty() or
00093 io.hasLiveCoeff.empty() or
00094 io.getLiveCoeff.empty() or
00095 io.setLiveCoeff.empty() or
00096 io.getJointNames.empty() or
00097 io.getActuatorNames.empty() or
00098 io.getCommandFile.empty())
00099 {
00100 std::stringstream err;
00101 err << "Constructor requires 'io.getUInt16', 'io.setUInt16', 'io.getMotorCoeff', 'io.hasLiveCoeff', 'io.getLiveCoeff', 'io.setLiveCoeff', io.getJointNames', 'io.getActuatorNames', and 'io.getCommandFile' be non-empty.";
00102 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::FATAL, err.str());
00103 throw std::invalid_argument(err.str());
00104 }
00105
00106 roboDynJoints = io.getJointNames(mechanism);
00107 roboDynActuators = io.getActuatorNames(mechanism);
00108
00109 if (roboDynJoints.size() != N or
00110 roboDynActuators.size() != N + 1)
00111 {
00112 std::stringstream err;
00113 err << "Constructor requires roboDynJoints have N and roboDynActuators have N+1 values, with N for this instance being " << N << std::endl;
00114 err << "Number of roboDynJoints: " << roboDynJoints.size() << std::endl;
00115 err << "Number of roboDynActuators: " << roboDynActuators.size() << std::endl;
00116 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::FATAL, err.str());
00117 throw std::invalid_argument(err.str());
00118
00119 }
00120
00121 timestep = 1 / freq;
00122 this->setParameters();
00123 }
00124
00125 template <unsigned int N>
00126 TubeTareMechanism<N>::~TubeTareMechanism()
00127 {}
00128
00129 template <unsigned int N>
00130 void TubeTareMechanism<N>::setParameters()
00131 {
00132 std::string parameterFile = io.getCommandFile(mechanism);
00133
00135 TiXmlDocument file(parameterFile.c_str());
00136 bool loadOkay = file.LoadFile();
00137
00138 if (!loadOkay)
00139 {
00140 std::stringstream err;
00141 err << "Failed to load file [" << parameterFile << "]";
00142 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::FATAL, err.str());
00143 throw std::runtime_error(err.str());
00144 }
00145
00146 TiXmlHandle doc(&file);
00147 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::INFO, "CommandFile [" + parameterFile + "] successfully loaded.");
00148
00149
00150 TiXmlHandle parametersElement(doc.FirstChildElement("ApiMap"));
00151
00152 if (parametersElement.ToElement())
00153 {
00155 std::stringstream str;
00156
00157 for (unsigned int i = 0; i < N + 1; ++i)
00158 {
00159 str.str("");
00160 str << "Actuator" << i << "EncoderState";
00161 encoderStateElements[i] = StringUtilities::makeFullyQualifiedRoboDynElement(roboDynActuators[i], ApiMap::getXmlElementValue(parametersElement, str.str()));
00162 str.str("");
00163 str << "Actuator" << i << "TensionAState";
00164 tensionAStateElements[i] = StringUtilities::makeFullyQualifiedRoboDynElement(roboDynActuators[i], ApiMap::getXmlElementValue(parametersElement, str.str()));
00165 str.str("");
00166 str << "Actuator" << i << "TensionBState";
00167 tensionBStateElements[i] = StringUtilities::makeFullyQualifiedRoboDynElement(roboDynActuators[i], ApiMap::getXmlElementValue(parametersElement, str.str()));
00168 str.str("");
00169 str << "Actuator" << i << "MotComCommand";
00170 motComCommandElements[i] = StringUtilities::makeFullyQualifiedRoboDynElement(roboDynActuators[i], ApiMap::getXmlElementValue(parametersElement, str.str()));
00171 }
00172
00173 for (unsigned int i = 0; i < N; ++i)
00174 {
00175 str.str("");
00176 str << "Joint" << i << "HallState";
00177 hallStateElements[i] = StringUtilities::makeFullyQualifiedRoboDynElement(roboDynJoints[i], ApiMap::getXmlElementValue(parametersElement, str.str()));
00178 }
00179
00181
00182 encoderVelZeroThreshold = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "EncoderVelZeroThreshold")));
00183 encoderMinTravel = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "EncoderMinTravel")));
00184 encoderMaxTravel = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "EncoderMaxTravel")));
00185
00186
00187 for (unsigned int i = 0; i < motComReleaseVal.rows(); ++i)
00188 {
00189 str.str("");
00190 str << "Actuator" << i << "MotComReleaseVal";
00191 motComReleaseVal[i] = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, str.str())));
00192 str.str("");
00193 str << "Actuator" << i << "MotComTightenVal";
00194 motComTightenVal[i] = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, str.str())));
00195 str.str("");
00196 }
00197
00198 double hallScale;
00199 typename FingerController<N>::JointVectorType hallCoeffs0, hallCoeffs1, hallCoeffs2, hallCoeffs3;
00200 hallScale = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "HallScaleFactor")));
00201
00202 for (unsigned int i = 0; i < hallCoeffs0.rows(); ++i)
00203 {
00204 str.str("");
00205 str << "Joint" << i << "HallCoeff0";
00206 hallCoeffs0[i] = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, str.str())));
00207 str.str("");
00208 str << "Joint" << i << "HallCoeff1";
00209 hallCoeffs1[i] = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, str.str())));
00210 str.str("");
00211 str << "Joint" << i << "HallCoeff2";
00212 hallCoeffs2[i] = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, str.str())));
00213 str.str("");
00214 str << "Joint" << i << "HallCoeff3";
00215 hallCoeffs3[i] = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, str.str())));
00216 }
00217
00218 finger.setHallAngleParameters(hallScale, hallCoeffs0, hallCoeffs1, hallCoeffs2, hallCoeffs3);
00219
00220
00221 for ( unsigned int i = 0; i < N + 1; i++)
00222 {
00223 str.str("");
00224 str << "Actuator" << i << "TensionAGain";
00225 tensionGainA[i] = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, str.str())));
00226 str.str("");
00227 str << "Actuator" << i << "TensionBGain";
00228 tensionGainB[i] = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, str.str())));
00229 str.str("");
00230 str << "Actuator" << i << "TensionSensorCalOffset";
00231 tensionSensorCalOffset[i] = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, str.str())));
00232 tension_out[i] = 0;
00233 }
00234
00235
00236
00237 for (unsigned int i = 0; i < N + 1; ++i)
00238 {
00239 encoderOffsetElements[i] = StringUtilities::makeFullyQualifiedRoboDynElement(roboDynActuators[i], "EncoderOffset");
00240 sliderOffsetElements[i] = StringUtilities::makeFullyQualifiedRoboDynElement(roboDynActuators[i], "SliderOffset");
00241 sliderTarePosElements[i] = StringUtilities::makeFullyQualifiedRoboDynElement(roboDynActuators[i], "SliderTarePosition");
00242 tensionOffsetElements[i] = StringUtilities::makeFullyQualifiedRoboDynElement(roboDynActuators[i], "TensionOffset");
00243 }
00244
00245
00246 positionAlpha = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "PositionAlpha")));
00247
00248
00249 tensionCounter = 0;
00250
00252 typename FingerController<N>::ReferenceMatrixType refMatrix;
00253
00254 for (unsigned int i = 0; i < refMatrix.rows(); ++i)
00255 {
00256 for (unsigned int j = 0; j < refMatrix.cols(); ++j)
00257 {
00258 str.str("");
00259 str << "ReferenceMatrix" << i << j;
00260 refMatrix(i, j) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, str.str())));
00261 }
00262 }
00263
00264 finger.setReferenceMatrix(refMatrix);
00265 }
00266 else
00267 {
00268 std::stringstream err;
00269 err << "The file " << parameterFile << " has no element named [ApiMap]";
00270 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::ERROR, err.str());
00271 throw std::runtime_error(err.str());
00272 }
00273 }
00274
00275
00276 template <unsigned int N>
00277 void TubeTareMechanism<N>::setStop(const std::vector<std::string>& actuators)
00278 {
00279
00280 if (actuators.empty())
00281 {
00282 std::stringstream err;
00283 err << "Stopping all actuators for " << mechanism;
00284 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::DEBUG, err.str());
00285
00286 for (unsigned int i = 0; i < motComCommandElements.size(); ++i)
00287 {
00288 io.setInt16(motComCommandElements[i], static_cast<int16_t>(0));
00289 }
00290 }
00291 else
00292 {
00293 for (unsigned int i = 0; i < roboDynActuators.size(); ++i)
00294 {
00295 if (std::find(actuators.begin(), actuators.end(), roboDynActuators[i]) != actuators.end() )
00296 {
00297 std::stringstream err;
00298 err << "Stopping " << mechanism << " actuator: " << roboDynActuators[i] << " motcomCommandElement: " << motComCommandElements[i];
00299 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::DEBUG, err.str());
00300 io.setInt16(motComCommandElements[i], static_cast<int16_t>(0));
00301 }
00302 }
00303 }
00304 }
00305
00306 template <unsigned int N>
00307 bool TubeTareMechanism<N>::isMoving()
00308 {
00309 for (unsigned int i = 0; i < encoderStateElements.size(); ++i)
00310 {
00311 encoderVec[i] = io.getInt16(encoderStateElements[i]);
00312 }
00313
00314
00315 if (!filterInitialized)
00316 {
00317 filteredEncoderVec = encoderVec;
00318 encoderVels.setZero();
00319 filterInitialized = true;
00320 }
00321 else
00322 {
00323 filteredEncoderVec = filteredEncoderVec * positionAlpha + encoderVec * (1 - positionAlpha);
00324 encoderVels = (filteredEncoderVec - prevEncoderVec) / timestep;
00325 }
00326
00327 prevEncoderVec = filteredEncoderVec;
00328
00329 for (unsigned int i = 0; i < encoderVels.size(); ++i)
00330 {
00331 if (-encoderVelZeroThreshold > encoderVels[i] || encoderVels[i] > encoderVelZeroThreshold)
00332 {
00333 return true;
00334 }
00335 }
00336
00337 return false;
00338 }
00339
00340 template <unsigned int N>
00341 void TubeTareMechanism<N>::setRelease(const std::vector<std::string>& actuators)
00342 {
00343 if (actuators.empty())
00344 {
00345 std::stringstream err;
00346 err << "Set release for all actuators in " << mechanism;
00347
00348 for (unsigned int i = 0; i < motComCommandElements.size(); ++i )
00349 {
00350 err << "\n\t" << motComCommandElements[i] << ": " << static_cast<int16_t>(motComReleaseVal[i]);
00351 io.setInt16(motComCommandElements[i], static_cast<int16_t>(motComReleaseVal[i]) );
00352 }
00353
00354 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::DEBUG, err.str());
00355 }
00356 else
00357 {
00358 for (unsigned int i = 0; i < roboDynActuators.size(); ++i)
00359 {
00360 if (std::find(actuators.begin(), actuators.end(), roboDynActuators[i]) != actuators.end() )
00361 {
00362 std::stringstream err;
00363 err << "Set release for " << mechanism << " actuator: " << roboDynActuators[i] << " motcomCommandElement: " << motComCommandElements[i];
00364 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::DEBUG, err.str());
00365 io.setInt16(motComCommandElements[i], static_cast<int16_t>(motComReleaseVal[i]));
00366 }
00367 }
00368 }
00369
00370 filterInitialized = false;
00371 }
00372
00373
00374 template <unsigned int N>
00375 void TubeTareMechanism<N>::getEncoderTarePos()
00376 {
00377 for (unsigned int i = 0; i < encoderOffsetElements.size(); ++i)
00378 {
00379 io.setLiveCoeff(encoderOffsetElements[i], io.getInt16(encoderStateElements[i]));
00380 }
00381 }
00382
00383 template <unsigned int N>
00384 void TubeTareMechanism<N>::setTighten(const std::vector<std::string>& actuators)
00385 {
00386 if (actuators.empty())
00387 {
00388 std::stringstream err;
00389 err << "Set tighten for all actuators in " << mechanism;
00390
00391 for (unsigned int i = 0; i < motComCommandElements.size(); ++i )
00392 {
00393 err << "\n\t" << motComCommandElements[i] << ": " << static_cast<int16_t>(motComTightenVal[i]);
00394 io.setInt16(motComCommandElements[i], static_cast<int16_t>(motComTightenVal[i]) );
00395 }
00396
00397 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::DEBUG, err.str());
00398 }
00399 else
00400 {
00401
00402 for (unsigned int i = 0; i < roboDynActuators.size(); ++i)
00403 {
00404
00405 if (std::find(actuators.begin(), actuators.end(), roboDynActuators[i]) != actuators.end() )
00406 {
00407 std::stringstream err;
00408 err << "Set tighten for " << mechanism << " actuator: " << roboDynActuators[i] << " motcomCommandElement: " << motComCommandElements[i];
00409 NasaCommonLogging::Logger::log("gov.nasa.robonet.TubeTareMechanism", log4cpp::Priority::DEBUG, err.str());
00410 io.setInt16(motComCommandElements[i], static_cast<int16_t>(motComTightenVal[i]));
00411 }
00412
00413
00414
00415
00416
00417 }
00418 }
00419
00420 filterInitialized = false;
00421 }
00422
00423 template <unsigned int N>
00424 int TubeTareMechanism<N>::goodPosition()
00425 {
00426
00427 for (unsigned int i = 0; i < encoderStateElements.size(); ++i)
00428 {
00429 int encoderAbsolute = io.getInt16(encoderStateElements[i]) - io.getLiveCoeff(encoderOffsetElements[i]);
00430
00431 if (-encoderMinTravel < encoderAbsolute && encoderAbsolute < encoderMinTravel)
00432 {
00433 return -1;
00434 }
00435
00436 if (encoderAbsolute < -encoderMaxTravel || encoderAbsolute > encoderMaxTravel)
00437 {
00438 return 1;
00439 }
00440 }
00441
00442 return 0;
00443
00444 }
00445
00446 template<unsigned int N>
00447 void TubeTareMechanism<N>::getSliderTarePos()
00448 {
00449 hallVec currentHalls;
00450 SliderVectorType sliderPos;
00451
00452 for (unsigned int i = 0; i < hallStateElements.size(); ++i)
00453 {
00454 currentHalls[i] = io.getUInt16(hallStateElements[i]);
00455 }
00456
00457 finger.getHallAngles(currentHalls, currentHalls);
00458 finger.getSlidersFromJoints(currentHalls, sliderPos);
00459
00460 for (unsigned int i = 0; i < sliderPos.size(); ++i)
00461 {
00462 io.setLiveCoeff(sliderOffsetElements[i], io.getInt16(encoderStateElements[i]));
00463 io.setLiveCoeff(sliderTarePosElements[i], sliderPos[i]);
00464 }
00465
00466 }
00467
00468 template<unsigned int N>
00469 void TubeTareMechanism<N>::getTensionTareValue()
00470 {
00471 SliderVectorType tensionA, tensionB;
00472
00473 tensionCounter++;
00474
00475 for (unsigned int i = 0; i < tensionAStateElements.size(); i++)
00476 {
00477 tensionA[i] = io.getUInt16(tensionAStateElements[i]);
00478 tensionB[i] = io.getUInt16(tensionBStateElements[i]);
00479 }
00480
00481 for (unsigned int i = 0; i < tension_out.size(); i++)
00482 {
00483
00484 double temp = tensionA[i] * tensionGainA[i] + tensionB[i] * tensionGainB[i] + tensionSensorCalOffset[i];
00485
00486
00487 tension_out[i] = ((tensionCounter - 1) * tension_out[i] + temp) / tensionCounter;
00488
00489
00490 io.setLiveCoeff(tensionOffsetElements[i], tension_out[i]);
00491 }
00492
00493 }
00494
00495 template<unsigned int N>
00496 void TubeTareMechanism<N>::resetTensionCounter()
00497 {
00498 tensionCounter = 0;
00499
00500 for (unsigned int i = 0; i < tension_out.size(); i++)
00501 {
00502 tension_out[i] = 0;
00503 }
00504 }
00505
00506 #endif // TUBE_TARE_UTILITIES_H