00001 #include "robodyn_mechanisms/JointCommandWrist.h"
00002 #include "r2_msgs/JointControlDataArray.h"
00003
00004 using namespace std;
00005 using namespace log4cpp;
00006 using namespace Eigen;
00007
00008 JointCommandWrist::JointCommandWrist(const std::string& mechanism, IoFunctions ioFunctions)
00009 : JointCommandInterface(mechanism, ioFunctions)
00010 , desiredPitchVel(0.f)
00011 , desiredYawVel(0.f)
00012 , sliderFilterInitialized(false)
00013 , hallFilterInitialized(false)
00014 , prevPosInitialized(false)
00015 , useHalls(true)
00016 , calFailureReported(false)
00017 , completeMessageSize(12)
00018 {
00019 if (mechanism == "")
00020 {
00021 stringstream err;
00022 err << "Constructor requires mechanism be non-empty.";
00023 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00024 throw invalid_argument(err.str());
00025 }
00026
00027 if (io.setInt16.empty())
00028 {
00029 stringstream err;
00030 err << "Constructor requires 'io.setInt16' to be non-empty.";
00031 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00032 throw invalid_argument(err.str());
00033 }
00034
00035 if (io.getInt16.empty())
00036 {
00037 stringstream err;
00038 err << "Constructor requires 'io.getInt16' to be non-empty.";
00039 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00040 throw invalid_argument(err.str());
00041 }
00042
00043 if (io.getUInt16.empty())
00044 {
00045 stringstream err;
00046 err << "Constructor requires 'io.getUInt16' to be non-empty.";
00047 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00048 throw invalid_argument(err.str());
00049 }
00050
00051 if (io.getBrainstemCoeff.empty())
00052 {
00053 stringstream err;
00054 err << "Constructor requires 'io.getBrainstemCoeff' to be non-empty.";
00055 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00056 throw invalid_argument(err.str());
00057 }
00058
00059 if (io.getMotorCoeff.empty())
00060 {
00061 stringstream err;
00062 err << "Constructor requires 'io.getMotorCoeff' to be non-empty.";
00063 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00064 throw invalid_argument(err.str());
00065 }
00066
00067 if (io.getMotorCoeff.empty())
00068 {
00069 stringstream err;
00070 err << "Constructor requires 'io.getMotorCoeff' to be non-empty.";
00071 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00072 throw invalid_argument(err.str());
00073 }
00074
00075 if (io.hasLiveCoeff.empty())
00076 {
00077 stringstream err;
00078 err << "Constructor requires 'io.hasLiveCoeff' to be non-empty.";
00079 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00080 throw invalid_argument(err.str());
00081 }
00082
00083 if (io.getLiveCoeff.empty())
00084 {
00085 stringstream err;
00086 err << "Constructor requires 'io.getLiveCoeff' to be non-empty.";
00087 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00088 throw invalid_argument(err.str());
00089 }
00090
00091 if (io.setLiveCoeff.empty())
00092 {
00093 stringstream err;
00094 err << "Constructor requires 'io.setLiveCoeff' to be non-empty.";
00095 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00096 throw invalid_argument(err.str());
00097 }
00098
00099 if (io.getJointNames.empty())
00100 {
00101 stringstream err;
00102 err << "Constructor requires 'io.getJointNames' to be non-empty.";
00103 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00104 throw invalid_argument(err.str());
00105 }
00106
00107 if (io.getActuatorNames.empty())
00108 {
00109 stringstream err;
00110 err << "Constructor requires 'io.getActuatorNames' to be non-empty.";
00111 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00112 throw invalid_argument(err.str());
00113 }
00114
00115 if (io.getCommandFile.empty())
00116 {
00117 stringstream err;
00118 err << "Constructor requires 'io.getCommandFile' to be non-empty.";
00119 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00120 throw invalid_argument(err.str());
00121 }
00122
00123 if (io.hasParam.empty())
00124 {
00125 stringstream err;
00126 err << "Constructor requires 'io.hasParam' to be non-empty.";
00127 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00128 throw invalid_argument(err.str());
00129 }
00130
00131 if (io.getDoubleParam.empty())
00132 {
00133 stringstream err;
00134 err << "Constructor requires 'io.getDoubleParam' to be non-empty.";
00135 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00136 throw invalid_argument(err.str());
00137 }
00138
00139 if (io.setDoubleParam.empty())
00140 {
00141 stringstream err;
00142 err << "Constructor requires 'io.setDoubleParam' to be non-empty.";
00143 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00144 throw invalid_argument(err.str());
00145 }
00146
00147 if (io.getBoolParam.empty())
00148 {
00149 stringstream err;
00150 err << "Constructor requires 'io.getBoolParam' to be non-empty.";
00151 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00152 throw invalid_argument(err.str());
00153 }
00154
00155 if (io.setBoolParam.empty())
00156 {
00157 stringstream err;
00158 err << "Constructor requires 'io.setBoolParam' to be non-empty.";
00159 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00160 throw invalid_argument(err.str());
00161 }
00162
00163 roboDynJoints = io.getJointNames(mechanism);
00164 roboDynActuators = io.getActuatorNames(mechanism);
00165
00166
00167 if (roboDynJoints.size() != 2 or
00168 roboDynActuators.size() != 2)
00169 {
00170 stringstream err;
00171 err << "Constructor requires roboDynJoints and roboDynActuators to have 2 values";
00172 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00173 throw invalid_argument(err.str());
00174
00175 }
00176
00177 if (roboDynJoints[0].find("pitch", 0) == string::npos)
00178 {
00179 stringstream err;
00180 err << "Expected pitch element, got " << roboDynJoints[0] << "." << std::endl;
00181 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00182 throw invalid_argument(err.str());
00183 }
00184
00185 if (roboDynJoints[1].find("yaw", 0) == string::npos)
00186 {
00187 stringstream err;
00188 err << "Expected yaw element, got " << roboDynJoints[1] << "." << std::endl;
00189 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00190 throw invalid_argument(err.str());
00191 }
00192
00193 if (roboDynActuators[0].find("thumbside", 0) == string::npos)
00194 {
00195 stringstream err;
00196 err << "Expected thumbside element, got " << roboDynActuators[0] << "." << std::endl;
00197 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00198 throw invalid_argument(err.str());
00199 }
00200
00201 if (roboDynActuators[1].find("littleside", 0) == string::npos)
00202 {
00203 stringstream err;
00204 err << "Expected littlside element, got " << roboDynActuators[1] << "." << std::endl;
00205 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00206 throw invalid_argument(err.str());
00207 }
00208
00209 wrist.reset(new WristMechanism());
00210 wristFault.reset(new WristMechanism());
00211 q1Controller.reset(new MultiLoopController());
00212 q2Controller.reset(new MultiLoopController());
00213
00214 loadCoeffs();
00215 }
00216
00217 JointCommandWrist::~JointCommandWrist()
00218 {
00219
00220 }
00221
00222 void JointCommandWrist::loadCoeffs()
00223 {
00224 io.setLiveCoeff(nameCoeffState, r2_msgs::JointControlCoeffState::NOTLOADED);
00225
00226 desiredPitchVel = 0.f;
00227 desiredYawVel = 0.f;
00228 sliderFilterInitialized = false;
00229 hallFilterInitialized = false;
00230 prevPosInitialized = false;
00231 calFailureReported = false;
00232
00233 std::string parameterFile = io.getCommandFile(mechanism);
00234
00236 namePitchLimit = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "PitchLimit");
00237 nameYawLimit = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "YawLimit");
00238 nameLittlesideSliderLimit = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "LittlesideSliderLimit");
00239 nameThumbsideSliderLimit = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "ThumbsideSliderLimit");
00240 nameSensorError = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "SensorError");
00241 nameSliderDiffError = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "SliderDiffError");
00242 nameCalibrationMode = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "CalibrationMode");
00243 nameCoeffState = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "CoeffState");
00244
00245 namePitchMaxValue = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "PitchMaxValue");
00246 namePitchMinValue = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "PitchMinValue");
00247 nameYawMaxValue = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "YawMaxValue");
00248 nameYawMinValue = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "YawMinValue");
00249 namePitchHallsValue = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "PitchHallsValue");
00250 namePitchCalcValue = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "PitchCalcValue");
00251 nameYawHallsValue = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "YawHallsValue");
00252 nameYawCalcValue = StringUtilities::makeFullyQualifiedRoboDynElement(mechanism, "YawCalcValue");
00253
00254
00256 simpleMeasuredStateMsg.name.resize(2);
00257 simpleMeasuredStateMsg.position.resize(2, 0.);
00258 simpleMeasuredStateMsg.velocity.resize(2, 0.);
00259 simpleMeasuredStateMsg.effort.resize(2, 0.);
00260
00261 simpleMeasuredStateMsg.name[0] = roboDynJoints[0];
00262 simpleMeasuredStateMsg.name[1] = roboDynJoints[1];
00263
00264 completeMeasuredStateMsg.name.resize(completeMessageSize);
00265 completeMeasuredStateMsg.position.resize(completeMessageSize, 0.);
00266 completeMeasuredStateMsg.velocity.resize(completeMessageSize, 0.);
00267 completeMeasuredStateMsg.effort.resize(completeMessageSize, 0.);
00268
00269 completeMeasuredStateMsg.name[0] = roboDynJoints[0];
00270 completeMeasuredStateMsg.name[1] = roboDynJoints[1];
00271 completeMeasuredStateMsg.name[2] = roboDynActuators[0];
00272 completeMeasuredStateMsg.name[3] = roboDynActuators[1];
00273 completeMeasuredStateMsg.name[4] = roboDynJoints.at(0) + StringUtilities::TOKEN_DELIMITER + string("halls");
00274 completeMeasuredStateMsg.name[5] = roboDynJoints.at(1) + StringUtilities::TOKEN_DELIMITER + string("halls");
00275 completeMeasuredStateMsg.name[6] = roboDynActuators.at(0) + StringUtilities::TOKEN_DELIMITER + string("encoder");
00276 completeMeasuredStateMsg.name[7] = roboDynActuators.at(1) + StringUtilities::TOKEN_DELIMITER + string("encoder");
00277 completeMeasuredStateMsg.name[8] = roboDynJoints.at(0) + StringUtilities::TOKEN_DELIMITER + string("embeddedCommand");
00278 completeMeasuredStateMsg.name[9] = roboDynJoints.at(1) + StringUtilities::TOKEN_DELIMITER + string("embeddedCommand");
00279 completeMeasuredStateMsg.name[10] = roboDynActuators.at(0) + StringUtilities::TOKEN_DELIMITER + string("embeddedCommand");
00280 completeMeasuredStateMsg.name[11] = roboDynActuators.at(1) + StringUtilities::TOKEN_DELIMITER + string("embeddedCommand");
00281
00282
00283 positionVals.resize(completeMessageSize, 0.);
00284 velocityVals.resize(completeMessageSize, 0.);
00285
00286 commandedStateMsg.name.resize(2);
00287 commandedStateMsg.desiredPosition.resize(2, 0.);
00288 commandedStateMsg.desiredPositionVelocityLimit.resize(2, 0.);
00289 commandedStateMsg.feedForwardTorque.resize(2, 0.);
00290 commandedStateMsg.proportionalGain.resize(2, 0.);
00291 commandedStateMsg.derivativeGain.resize(2, 0.);
00292 commandedStateMsg.integralGain.resize(2, 0.);
00293 commandedStateMsg.positionLoopTorqueLimit.resize(2, 0.);
00294 commandedStateMsg.positionLoopWindupLimit.resize(2, 0.);
00295 commandedStateMsg.torqueLoopVelocityLimit.resize(2, 0.);
00296
00297 commandedStateMsg.name[0] = roboDynJoints[0];
00298 commandedStateMsg.name[1] = roboDynJoints[1];
00299 commandedStateMsg.desiredPosition[0] = 0;
00300 commandedStateMsg.desiredPosition[1] = 0;
00301
00302 jointCapabilityMsg.name.resize(2);
00303 jointCapabilityMsg.positionLimitMax.resize(2, 0.);
00304 jointCapabilityMsg.positionLimitMin.resize(2, 0.);
00305 jointCapabilityMsg.velocityLimit.resize(2, 30.);
00306 jointCapabilityMsg.torqueLimit.resize(2, 0.);
00307
00308 jointCapabilityMsg.name[0] = roboDynJoints[0];
00309 jointCapabilityMsg.name[1] = roboDynJoints[1];
00310
00312 TiXmlDocument file(parameterFile.c_str());
00313 bool loadOkay = file.LoadFile();
00314
00315 if (!loadOkay)
00316 {
00317 stringstream err;
00318 err << "Failed to load file [" << parameterFile << "]";
00319 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::FATAL, err.str());
00320 throw runtime_error(err.str());
00321 }
00322
00323 TiXmlHandle doc(&file);
00324 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::INFO, "CommandFile [" + parameterFile + "] successfully loaded.");
00325
00326
00327 TiXmlHandle parametersElement(doc.FirstChildElement("ApiMap"));
00328
00329 if (parametersElement.ToElement())
00330 {
00331
00333 encoderThumbPositionStatusElement = StringUtilities::makeFullyQualifiedRoboDynElement( roboDynActuators[0], ApiMap::getXmlElementValue(parametersElement, "EncoderThumbSidePositionStatus"));
00334 encoderLittlePositionStatusElement = StringUtilities::makeFullyQualifiedRoboDynElement( roboDynActuators[1], ApiMap::getXmlElementValue(parametersElement, "EncoderLittleSidePositionStatus"));
00335 hallsPitchStatusElement = StringUtilities::makeFullyQualifiedRoboDynElement( roboDynJoints[0], ApiMap::getXmlElementValue(parametersElement, "HallsPitchStatus"));
00336 hallsYawStatusElement = StringUtilities::makeFullyQualifiedRoboDynElement( roboDynJoints[1], ApiMap::getXmlElementValue(parametersElement, "HallsYawStatus"));
00337
00339 desiredMotComThumbCommandElement = StringUtilities::makeFullyQualifiedRoboDynElement( roboDynActuators[0], ApiMap::getXmlElementValue(parametersElement, "DesiredMotComThumbSideCommand"));
00340 desiredMotComLittleCommandElement = StringUtilities::makeFullyQualifiedRoboDynElement( roboDynActuators[1], ApiMap::getXmlElementValue(parametersElement, "DesiredMotComLittleSideCommand"));
00341
00343 double bypass = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "PositionLoopBypass")));
00344 sliderMinPosition = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderMinPositionCommand")));
00345 sliderMaxPosition = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderMaxPositionCommand")));
00346 double pKp = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderKpGainCommand")));
00347
00348 q1Controller->setPositionLoopParameters(sliderMinPosition, sliderMaxPosition, pKp, bypass <= 0 ? false : true);
00349 q2Controller->setPositionLoopParameters(sliderMinPosition, sliderMaxPosition, pKp, bypass <= 0 ? false : true);
00350
00351
00352 q1Controller->setTorqueLoopParameters(0., 0., 0., 0., true);
00353 q2Controller->setTorqueLoopParameters(0., 0., 0., 0., true);
00354
00355 bypass = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "VelocityLoopBypass")));
00356 double minVelocity = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderMinVelocityCommand" )));
00357 double maxVelocity = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderMaxVelocityCommand" )));
00358 double vKp = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderVelocityKpGainCommand" )));
00359 double vKi = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderVelocityKiGainCommand" )));
00360 double windup = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderIntegratorWindupLimit" )));
00361
00362 q1Controller->setVelocityLoopParameters(minVelocity, maxVelocity, vKp, vKi, windup, bypass <= 0 ? false : true);
00363 q2Controller->setVelocityLoopParameters(minVelocity, maxVelocity, vKp, vKi, windup, bypass <= 0 ? false : true);
00364
00365 bypass = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "CurrentLoopBypass")));
00366 double minCurrent = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderMinCurrentCommand" )));
00367 double maxCurrent = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderMaxCurrentCommand" )));
00368 double maxDutyCycle = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderMaxDutyCycleCommand" )));
00369
00370 q1Controller->setCurrentLoopParameters(minCurrent, maxCurrent, maxDutyCycle, bypass <= 0 ? false : true);
00371 q2Controller->setCurrentLoopParameters(minCurrent, maxCurrent, maxDutyCycle, bypass <= 0 ? false : true);
00372
00373 double motorViscousDampingComp = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "MotorViscousDampingCompensation" )));
00374 double motorInertia = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "MotorInertia" )));
00375 double motorTorqueConst = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "MotorTorqueConstant" )));
00376 double motorPhaseRes = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "MotorPhaseResistance" )));
00377 double motorBackEMF = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "MotorBackEMFConstant" )));
00378 double motorInductance = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "MotorInductance" )));
00379 double motionRatio = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "MotionRatio" )));
00380 double PWMFreq = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "PWMFrequency" )));
00381 double bridgeDeadTime = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "BridgeDeadTime" )));
00382 double bridgeSwitchTime = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "BridgeSwitchTime" )));
00383
00384 q1Controller->setHardwareParameters(motorViscousDampingComp, motorInertia, motorTorqueConst, motorPhaseRes, motorBackEMF, motorInductance, motionRatio, PWMFreq, bridgeDeadTime, bridgeSwitchTime);
00385 q2Controller->setHardwareParameters(motorViscousDampingComp, motorInertia, motorTorqueConst, motorPhaseRes, motorBackEMF, motorInductance, motionRatio, PWMFreq, bridgeDeadTime, bridgeSwitchTime);
00386
00387 busVoltage = io.getBrainstemCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "BusVoltage")));
00388
00389
00390 positionAlpha = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "PositionAlpha")));
00391 timestep = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Timestep")));
00392
00393
00394 EmbeddedSmoother::Settings smoothSettings;
00395
00396 if (timestep <= 0.)
00397 {
00398 throw std::runtime_error("invalid timestep");
00399 }
00400
00401 smoothSettings.timestep = timestep;
00402 smoothSettings.minVel = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "VelocityMinPitch")));
00403 smoothSettings.maxAcc = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "AccelerationMaxPitch")));
00404 smoothSettings.accGain = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "AccelerationGainPitch")));
00405 smootherPitch.reset(new EmbeddedSmoother(smoothSettings));
00406 smoothSettings.minVel = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "VelocityMinYaw")));
00407 smoothSettings.maxAcc = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "AccelerationMaxYaw")));
00408 smoothSettings.accGain = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "AccelerationGainYaw")));
00409 smootherYaw.reset(new EmbeddedSmoother(smoothSettings));
00410
00411
00412 q1Controller->setLoopRate(1 / timestep);
00413 q2Controller->setLoopRate(1 / timestep);
00414
00416 Vector3d a, a0, b, c, d, d0, pitch, yaw, m, n;
00417
00418 a(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Ax")));
00419 a(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Ay")));
00420 a(2) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Az")));
00421
00422 a0(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "A0x")));
00423 a0(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "A0y")));
00424 a0(2) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "A0z")));
00425
00426 b(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Bx")));
00427 b(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "By")));
00428 b(2) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Bz")));
00429
00430 c(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Cx")));
00431 c(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Cy")));
00432 c(2) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Cz")));
00433
00434 d(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Dx")));
00435 d(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Dy")));
00436 d(2) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Dz")));
00437
00438 d0(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "D0x")));
00439 d0(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "D0y")));
00440 d0(2) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "D0z")));
00441
00442 pitch(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Pitchx")));
00443 pitch(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Pitchy")));
00444 pitch(2) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Pitchz")));
00445
00446 yaw(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Yawx")));
00447 yaw(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Yawy")));
00448 yaw(2) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Yawz")));
00449
00450 m(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "PitchAxisx")));
00451 m(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "PitchAxisy")));
00452 m(2) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "PitchAxisz")));
00453
00454 n(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "YawAxisx")));
00455 n(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "YawAxisy")));
00456 n(2) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "YawAxisz")));
00457
00458 double linkLength = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "LinkLength")));
00459
00460 wrist->loadDesignParams(a, a0, b, c, d, d0, pitch, yaw, m, n, linkLength);
00461
00463 double upperPitchMax = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "UpperPitchMax")));
00464 double upperPitchMin = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "UpperPitchMin")));
00465 double lowerPitchMax = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "LowerPitchMax")));
00466 double lowerPitchMin = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "LowerPitchMin")));
00467 double upperYawMax = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "UpperYawMax")));
00468 double upperYawMin = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "UpperYawMin")));
00469 double lowerYawMax = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "LowerYawMax")));
00470 double lowerYawMin = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "LowerYawMin")));
00471
00472 wrist->setLimits(upperPitchMin, upperPitchMax, lowerPitchMin, lowerPitchMax, upperYawMin, upperYawMax, lowerYawMin, lowerYawMax);
00473
00475 Vector2d sliderOffset, sliderGain, angleOffset, angleGain;
00476 sliderOffset(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "ThumbSliderOffset")));
00477 sliderOffset(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "LittleSliderOffset")));
00478
00479 sliderGain(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "ThumbSliderGain")));
00480 sliderGain(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "LittleSliderGain")));
00481
00482 angleOffset(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "PitchOffset")));
00483 angleOffset(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "YawOffset")));
00484
00485 angleGain(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "PitchGain")));
00486 angleGain(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "YawGain")));
00487
00488 wrist->setSliderOffsetGain(sliderOffset, sliderGain);
00489 wrist->setAngleOffsetGain(angleOffset, angleGain);
00490
00491 wrist->maxIt = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "MaxIter")));
00492 wrist->eps = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "Eps")));
00493
00494 hta.resize(2);
00495 double coeff1, coeff2, coeff3, coeff4, scaleFactor;
00496 coeff1 = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "HallPitchCoeff1")));
00497 coeff2 = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "HallPitchCoeff2")));
00498 coeff3 = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "HallPitchCoeff3")));
00499 coeff4 = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "HallPitchCoeff4")));
00500 scaleFactor = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "HallScaleFactor")));
00501 hta[0].useCoeffs(coeff1, coeff2, coeff3, coeff4, scaleFactor);
00502 coeff1 = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "HallYawCoeff1")));
00503 coeff2 = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "HallYawCoeff2")));
00504 coeff3 = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "HallYawCoeff3")));
00505 coeff4 = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "HallYawCoeff4")));
00506 hta[1].useCoeffs(coeff1, coeff2, coeff3, coeff4, scaleFactor);
00507
00509 maxSensorErrorFault = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "MaxSensorError")));
00510 maxSliderDiffFault = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "MaxSliderDiffFault")));
00511 sliderMinPositionFault = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderMinPositionFault")));
00512 sliderMaxPositionFault = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "SliderMaxPositionFault")));
00513 upperPitchMax = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "UpperPitchMaxFault")));
00514 upperPitchMin = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "UpperPitchMinFault")));
00515 lowerPitchMax = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "LowerPitchMaxFault")));
00516 lowerPitchMin = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "LowerPitchMinFault")));
00517 upperYawMax = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "UpperYawMaxFault")));
00518 upperYawMin = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "UpperYawMinFault")));
00519 lowerYawMax = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "LowerYawMaxFault")));
00520 lowerYawMin = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "LowerYawMinFault")));
00521 wristFault->setLimits(upperPitchMin, upperPitchMax, lowerPitchMin, lowerPitchMax, upperYawMin, upperYawMax, lowerYawMin, lowerYawMax);
00522
00525 nameUseHalls = StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, "UseHalls");
00526 nameManualCalThumbSlider = StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "ManualCalThumbSlider"));
00527 nameManualCalLittleSlider = StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "ManualCalLittleSlider"));
00528 nameManualCalPitch = StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "ManualCalPitch"));
00529 nameManualCalYaw = StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "ManualCalYaw"));
00530
00531 manualCalSliderPos(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "ManualCalThumbSlider")));
00532 manualCalSliderPos(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "ManualCalLittleSlider")));
00533 manualCalAng(0) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "ManualCalPitch")));
00534 manualCalAng(1) = io.getMotorCoeff(StringUtilities::makeFullyQualifiedRoboDynElement( mechanism, ApiMap::getXmlElementValue(parametersElement, "ManualCalYaw")));
00535
00537 io.setLiveCoeff(namePitchLimit, 0.);
00538 io.setLiveCoeff(nameYawLimit, 0.);
00539 io.setLiveCoeff(nameLittlesideSliderLimit, 0.);
00540 io.setLiveCoeff(nameThumbsideSliderLimit, 0.);
00541 io.setLiveCoeff(nameSensorError, 0.);
00542 io.setLiveCoeff(nameSliderDiffError, 0.);
00543
00544 io.setLiveCoeff(namePitchMaxValue, -999);
00545 io.setLiveCoeff(namePitchMinValue, 999);
00546 io.setLiveCoeff(nameYawMaxValue, -999);
00547 io.setLiveCoeff(nameYawMinValue, 999);
00548 io.setLiveCoeff(namePitchHallsValue, 0);
00549 io.setLiveCoeff(namePitchCalcValue, 0);
00550 io.setLiveCoeff(nameYawHallsValue, 0);
00551 io.setLiveCoeff(nameYawCalcValue, 0);
00552
00553 io.setBoolParam(nameUseHalls, useHalls);
00554 io.setDoubleParam(nameManualCalThumbSlider, manualCalSliderPos(0));
00555 io.setDoubleParam(nameManualCalLittleSlider, manualCalSliderPos(1));
00556 io.setDoubleParam(nameManualCalPitch, manualCalAng(0));
00557 io.setDoubleParam(nameManualCalYaw, manualCalAng(1));
00558
00560 wrist->isCalibrated = false;
00561 calCalled = false;
00562 calibrationState.state = r2_msgs::JointControlCalibrationMode::UNCALIBRATED;
00563 io.setLiveCoeff(nameCoeffState, r2_msgs::JointControlCoeffState::LOADED);
00564
00565 desiredQ1 = manualCalSliderPos(0);
00566 desiredQ2 = manualCalSliderPos(1);
00567 desiredPitch = manualCalAng(0);
00568 desiredYaw = manualCalAng(1);
00569 desiredSlider = Vector2d::Zero();
00570 desiredAngle = Vector2d::Zero();
00571 filteredSlider = Vector2d::Zero();
00572 }
00573 else
00574 {
00575 stringstream err;
00576 err << "The file " << parameterFile << " has no element named [ApiMap]";
00577 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::ERROR, err.str());
00578 throw runtime_error(err.str());
00579 }
00580 }
00581
00582 void JointCommandWrist::updateMeasuredState(r2_msgs::JointControlData msg)
00583 {
00584
00585 if (msg.coeffState.state != r2_msgs::JointControlCoeffState::LOADED)
00586 {
00587 positionVals.assign(completeMessageSize, 0.0);
00588 velocityVals.assign(completeMessageSize, 0.0);
00589 return;
00590 }
00591
00592 if (!io.hasLiveCoeff(nameCalibrationMode))
00593 {
00594 stringstream err;
00595 err << "Live coeff [" << nameCalibrationMode << "] does not exist.";
00596 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::ERROR, err.str());
00597 throw runtime_error(err.str());
00598 }
00599
00600 if (!io.hasParam(nameUseHalls))
00601 {
00602 stringstream err;
00603 err << "param [" << nameUseHalls << "] does not exist.";
00604 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::ERROR, err.str());
00605 throw runtime_error(err.str());
00606 }
00607
00608 encoder = Vector2d::Zero();
00609 halls = Vector2d::Zero();
00610 Vector2d slider = Vector2d::Zero();
00611 ang = Vector2d::Zero();
00612
00613 encoder(0) = io.getInt16(encoderThumbPositionStatusElement);
00614 encoder(1) = io.getInt16(encoderLittlePositionStatusElement);
00615 io.getBoolParam(nameUseHalls, useHalls);
00616
00617 if (useHalls)
00618 {
00619 halls(0) = hta[0].getAngleFromHalls(io.getUInt16(hallsPitchStatusElement));
00620 halls(1) = hta[1].getAngleFromHalls(io.getUInt16(hallsYawStatusElement));
00621
00622
00623 if (!hallFilterInitialized)
00624 {
00625 filteredHalls = halls;
00626 hallFilterInitialized = true;
00627 }
00628
00629 filteredHalls = filteredHalls * positionAlpha + halls * (1 - positionAlpha);
00630 }
00631 else
00632 {
00633 halls(0) = io.getUInt16(hallsPitchStatusElement);
00634 halls(1) = io.getUInt16(hallsYawStatusElement);
00635 }
00636
00637 if (calibrationState.state == r2_msgs::JointControlCalibrationMode::UNCALIBRATED)
00638 {
00639
00640 }
00641 else if (calibrationState.state == r2_msgs::JointControlCalibrationMode::ENABLE)
00642 {
00643 if (useHalls)
00644 {
00645
00646 Vector2d calSlider;
00647
00648 try
00649 {
00650 double upperPitch, lowerPitch, upperYaw, lowerYaw;
00651 wrist->getLimits(halls(0), halls(1), upperPitch, lowerPitch, upperYaw, lowerYaw);
00652
00653 if (halls(0) > upperPitch || halls(0) < lowerPitch
00654 || halls(1) > upperYaw || halls(1) < lowerYaw)
00655 {
00656 stringstream ss;
00657 ss << "Halls data outside of limits; pitch: " << halls(0) << ", upper limit: " << upperPitch << ", lower limit: " << lowerPitch << "; yaw: " << halls(1) << " upper limit: " << upperYaw << ", lower limit: " << lowerYaw;
00658 throw std::runtime_error(ss.str());
00659 }
00660
00661 calSlider = wrist->getSliderFromAngle(halls);
00662 stringstream ss;
00663 ss << "Halls calibration on " << mechanism << std::endl;
00664 ss << "slider pos: (" << calSlider(0) << "," << calSlider(1) << "), angle: (" << halls(0) << "," << halls(1) << ")";
00665 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::NOTICE, ss.str());
00666 wrist->calWrist(encoder, calSlider, halls);
00668 wrist->getSliderFromWristEncoder(encoder);
00669
00670 if (wrist->isCalibrated)
00671 {
00672 io.setLiveCoeff(nameCalibrationMode, r2_msgs::JointControlCalibrationMode::DISABLE);
00673 calibrationState.state = r2_msgs::JointControlCalibrationMode::DISABLE;
00674 stringstream ss;
00675 ss << "Calibrated wrist";
00676 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::DEBUG, ss.str());
00677 calFailureReported = false;
00678 }
00679 else
00680 {
00681 if (!calFailureReported)
00682 {
00683 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::WARN, "Calibration failed.. remaining uncalibrated");
00684 calFailureReported = true;
00685 }
00686
00687 return;
00688 }
00689 }
00690 catch (std::exception& e)
00691 {
00692 wrist->isCalibrated = false;
00693
00694 if (!calFailureReported)
00695 {
00696 stringstream ss;
00697 ss << "Calibration failed (" << e.what() << "): remaining uncalibrated";
00698 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::WARN, ss.str());
00699 calFailureReported = true;
00700 }
00701
00702 return;
00703 }
00704 }
00705 else
00706 {
00707
00708 if (!io.getDoubleParam(nameManualCalThumbSlider, manualCalSliderPos(0)) ||
00709 !io.getDoubleParam(nameManualCalLittleSlider, manualCalSliderPos(1)) ||
00710 !io.getDoubleParam(nameManualCalPitch, manualCalAng(0)) ||
00711 !io.getDoubleParam(nameManualCalYaw, manualCalAng(1)))
00712 {
00713 stringstream err;
00714 err << "Invalid params for manual cal.";
00715 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::ERROR, err.str());
00716 throw runtime_error(err.str());
00717 }
00718
00719 stringstream ss;
00720 ss << "Manual calibration on " << mechanism << std::endl;
00721 ss << "slider pos: (" << manualCalSliderPos(0) << "," << manualCalSliderPos(1) << "), angle: (" << manualCalAng(0) << "," << manualCalAng(1) << ")";
00722 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::NOTICE, ss.str());
00723 wrist->calWrist(encoder, manualCalSliderPos, manualCalAng);
00724
00725 if (wrist->isCalibrated)
00726 {
00727 io.setLiveCoeff(nameCalibrationMode, r2_msgs::JointControlCalibrationMode::DISABLE);
00728 calibrationState.state = r2_msgs::JointControlCalibrationMode::DISABLE;
00729 stringstream ss;
00730 ss << "Calibrated wrist";
00731 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::DEBUG, ss.str());
00732 calFailureReported = false;
00733 }
00734 else
00735 {
00736 if (!calFailureReported)
00737 {
00738 stringstream ss;
00739 ss << "Manual calibration failed.. remaining uncalibrated";
00740 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::WARN, ss.str());
00741 calFailureReported = true;
00742 }
00743
00744 return;
00745 }
00746 }
00747 }
00748 else if (calibrationState.state == r2_msgs::JointControlCalibrationMode::DISABLE)
00749 {
00750 if (wrist->isCalibrated)
00751 {
00752 slider = wrist->getSliderFromWristEncoder(encoder);
00753
00754
00755 if (!sliderFilterInitialized)
00756 {
00757 filteredSlider = slider;
00758 sliderFilterInitialized = true;
00759 }
00760
00761 filteredSlider = filteredSlider * positionAlpha + slider * (1 - positionAlpha);
00762
00763 try
00764 {
00765 ang = wrist->getAngleFromSlider(filteredSlider);
00766 fwdKinFault = false;
00767 }
00768 catch (std::runtime_error)
00769 {
00771 if (!fwdKinFault)
00772 {
00773 stringstream ss;
00774 ss << "Unable to find fwd kinematics";
00775 NasaCommonLogging::Logger::log("gov.nasa.robonet.JointCommandWrist", Priority::WARN, ss.str());
00776 fwdKinFault = true;
00777 }
00778
00779 if (useHalls)
00780 {
00781 ang = halls;
00782 }
00783 }
00784 }
00785
00786 setFaultState();
00787
00788 }
00789
00790 positionVals[0] = ang(0);
00791 positionVals[1] = ang(1);
00792 positionVals[2] = filteredSlider(0);
00793 positionVals[3] = filteredSlider(1);
00794 positionVals[4] = halls(0);
00795 positionVals[5] = halls(1);
00796 positionVals[6] = encoder(0);
00797 positionVals[7] = encoder(1);
00798 positionVals[8] = smoothedPitch;
00799 positionVals[9] = smoothedYaw;
00800 positionVals[10] = desiredQ1;
00801 positionVals[11] = desiredQ2;
00802
00803
00804 if (!prevPosInitialized)
00805 {
00806 velocityVals.assign(velocityVals.size(), 0.);
00807 prevPosInitialized = true;
00808 }
00809 else
00810 {
00811 for (unsigned int i = 0; i < velocityVals.size(); ++i)
00812 {
00813 velocityVals[i] = (positionVals[i] - prevPositionVals[i]) / timestep;
00814 }
00815 }
00816
00817 prevPositionVals = positionVals;
00818
00819 angVel(0) = (double)velocityVals[0];
00820 angVel(1) = (double)velocityVals[1];
00821 sliderVel(0) = (double)velocityVals[2];
00822 sliderVel(1) = (double)velocityVals[3];
00823 hallsVel(0) = (double)velocityVals[4];
00824 hallsVel(1) = (double)velocityVals[5];
00825 encoderVel(0) = (double)velocityVals[6];
00826 encoderVel(1) = (double)velocityVals[7];
00827 velocityVals[10] = sliderVelCommand(0);
00828 velocityVals[11] = sliderVelCommand(1);
00829
00830 return;
00831 }
00832
00833 sensor_msgs::JointState JointCommandWrist::getSimpleMeasuredState()
00834 {
00835 simpleMeasuredStateMsg.header.stamp = ros::Time::now();
00836
00837 simpleMeasuredStateMsg.position[0] = positionVals[0];
00838 simpleMeasuredStateMsg.position[1] = positionVals[1];
00839
00840 simpleMeasuredStateMsg.velocity[0] = velocityVals[0];
00841 simpleMeasuredStateMsg.velocity[1] = velocityVals[1];
00842
00843 return simpleMeasuredStateMsg;
00844 }
00845
00846 sensor_msgs::JointState JointCommandWrist::getCompleteMeasuredState()
00847 {
00848 completeMeasuredStateMsg.header.stamp = ros::Time::now();
00849
00850 completeMeasuredStateMsg.position = positionVals;
00851 completeMeasuredStateMsg.velocity = velocityVals;
00852
00853 return completeMeasuredStateMsg;
00854 }
00855
00856 void JointCommandWrist::setFaultState()
00857 {
00859 double up;
00860 double lp;
00861 double uy;
00862 double ly;
00863
00864 wristFault->getLimits(ang(0), ang(1), up, lp, uy, ly);
00865
00866 if (ang(0) > up || ang(0) < lp)
00867 {
00868 io.setLiveCoeff(namePitchLimit, 1.);
00869 io.setLiveCoeff(namePitchMaxValue, ang(0));
00870 io.setLiveCoeff(namePitchMinValue, ang(0));
00871 }
00872 else
00873 {
00874 io.setLiveCoeff(namePitchLimit, 0.);
00875 io.setLiveCoeff(namePitchMaxValue, -999);
00876 io.setLiveCoeff(namePitchMinValue, 999);
00877 }
00878
00879 if (ang(1) > uy || ang(1) < ly)
00880 {
00881 io.setLiveCoeff(nameYawLimit, 1.);
00882 io.setLiveCoeff(nameYawMaxValue, ang(1));
00883 io.setLiveCoeff(nameYawMinValue, ang(1));
00884 }
00885 else
00886 {
00887 io.setLiveCoeff(nameYawLimit, 0.);
00888 io.setLiveCoeff(nameYawMaxValue, -999);
00889 io.setLiveCoeff(nameYawMinValue, 999);
00890 }
00891
00893 if (filteredSlider(0) > sliderMaxPositionFault || filteredSlider(0) < sliderMinPositionFault)
00894 {
00895 io.setLiveCoeff(nameThumbsideSliderLimit, 1.);
00896 }
00897 else
00898 {
00899 io.setLiveCoeff(nameThumbsideSliderLimit, 0.);
00900 }
00901
00902 if (filteredSlider(1) > sliderMaxPositionFault || filteredSlider(1) < sliderMinPositionFault)
00903 {
00904 io.setLiveCoeff(nameLittlesideSliderLimit, 1.);
00905 }
00906 else
00907 {
00908 io.setLiveCoeff(nameLittlesideSliderLimit, 0.);
00909 }
00910
00912 if (useHalls)
00913 {
00914 if (fabs(ang(0) - halls(0)) > maxSensorErrorFault || fabs(ang(1) - halls(1)) > maxSensorErrorFault)
00915 {
00916 io.setLiveCoeff(nameSensorError, 1.);
00917 io.setLiveCoeff(namePitchHallsValue, halls(0));
00918 io.setLiveCoeff(namePitchCalcValue, ang(0));
00919 io.setLiveCoeff(nameYawHallsValue, halls(1));
00920 io.setLiveCoeff(nameYawCalcValue, ang(1));
00921 }
00922 else
00923 {
00924 io.setLiveCoeff(nameSensorError, 0.);
00925 io.setLiveCoeff(namePitchHallsValue, 0.);
00926 io.setLiveCoeff(namePitchCalcValue, 0.);
00927 io.setLiveCoeff(nameYawHallsValue, 0.);
00928 io.setLiveCoeff(nameYawCalcValue, 0.);
00929 }
00930 }
00931 else
00932 {
00933 io.setLiveCoeff(nameSensorError, 0.);
00934 io.setLiveCoeff(namePitchHallsValue, 0.);
00935 io.setLiveCoeff(namePitchCalcValue, 0.);
00936 io.setLiveCoeff(nameYawHallsValue, 0.);
00937 io.setLiveCoeff(nameYawCalcValue, 0.);
00938 }
00939
00941 if (fabs(filteredSlider(0) - filteredSlider(1)) > maxSliderDiffFault)
00942 {
00943 io.setLiveCoeff(nameSliderDiffError, 1.);
00944 }
00945 else
00946 {
00947 io.setLiveCoeff(nameSliderDiffError, 0.);
00948 }
00949
00950 }
00951
00952 r2_msgs::JointCommand JointCommandWrist::getCommandedState()
00953 {
00954 commandedStateMsg.header.stamp = ros::Time::now();
00955 return commandedStateMsg;
00956 }
00957
00958 void JointCommandWrist::setCommand(r2_msgs::JointCommand msg, r2_msgs::JointControlData control)
00959 {
00960 if (!calCalled && control.calibrationMode.state == r2_msgs::JointControlCalibrationMode::ENABLE)
00961 {
00962 calibrationState.state = r2_msgs::JointControlCalibrationMode::ENABLE;
00963 calCalled = true;
00964 }
00965
00966 if (control.calibrationMode.state == r2_msgs::JointControlCalibrationMode::DISABLE)
00967 {
00968 calCalled = false;
00969 }
00970
00972 if (!msg.name.empty() && !msg.desiredPosition.empty())
00973 {
00974 if (msg.desiredPositionVelocityLimit.empty())
00975 {
00976 msg.desiredPositionVelocityLimit.resize(msg.name.size(), 0.);
00977 }
00978
00980 if (control.commandMode.state == r2_msgs::JointControlCommandMode::MOTCOM)
00981 {
00982 for (unsigned int i = 0; i < msg.name.size(); ++i)
00983 {
00984 if (msg.name[i] == roboDynActuators[0])
00985 {
00986 desiredQ1 = msg.desiredPosition[i];
00987 }
00988 else if (msg.name[i] == roboDynActuators[1])
00989 {
00990 desiredQ2 = msg.desiredPosition[i];
00991 }
00992 }
00993 }
00994 else if (control.commandMode.state == r2_msgs::JointControlCommandMode::ACTUATOR)
00995 {
00996 for (unsigned int i = 0; i < msg.name.size(); ++i)
00997 {
00998 if (msg.name[i] == roboDynActuators[0])
00999 {
01000 desiredQ1 = msg.desiredPosition[i];
01001 }
01002 else if (msg.name[i] == roboDynActuators[1])
01003 {
01004 desiredQ2 = msg.desiredPosition[i];
01005 }
01006 }
01007
01008 try
01009 {
01010
01011 desiredAngle = wrist->getAngleFromSlider(Vector2d(desiredQ1, desiredQ2));
01012 wrist->applyLimits(desiredAngle(0), desiredAngle(1));
01013
01014
01015 smoothedPitch = smootherPitch->reset(desiredAngle(0), 0.);
01016 smoothedYaw = smootherYaw->reset(desiredAngle(1), 0.);
01017
01018 commandedStateMsg.desiredPosition[0] = desiredAngle(0);
01019 commandedStateMsg.desiredPosition[1] = desiredAngle(1);
01020 commandedStateMsg.desiredPositionVelocityLimit[0] = 0;
01021 commandedStateMsg.desiredPositionVelocityLimit[1] = 0;
01022 }
01023 catch (std::runtime_error& e)
01024 {
01026 NasaCommonLogging::Logger::getCategory("gov.nasa.robonet.JointCommandWrist") << log4cpp::Priority::ERROR << "Kinematics failed with error " << e.what() << " on (" << desiredQ1 << "," << desiredQ2 << " command to actuators " << roboDynActuators[0] << ", " << roboDynActuators[1];
01027 control.controlMode.state = r2_msgs::JointControlMode::PARK;
01028 }
01029
01030 }
01031 else
01032 {
01033 if (msg.desiredPositionVelocityLimit.empty())
01034 {
01035 msg.desiredPositionVelocityLimit.resize(msg.name.size(), 0);
01036 }
01037
01038 for (unsigned int i = 0; i < msg.name.size(); ++i)
01039 {
01040 if (msg.name[i] == roboDynJoints[0])
01041 {
01042 desiredPitch = msg.desiredPosition[i];
01043 desiredPitchVel = msg.desiredPositionVelocityLimit[i];
01044 }
01045 else if (msg.name[i] == roboDynJoints[1])
01046 {
01047 desiredYaw = msg.desiredPosition[i];
01048 desiredYawVel = msg.desiredPositionVelocityLimit[i];
01049 }
01050 }
01051
01052 try
01053 {
01054 if (control.controlMode.state == r2_msgs::JointControlMode::DRIVE)
01055 {
01056
01057 smoothedPitch = smootherPitch->update(desiredPitch, desiredPitchVel);
01058 smoothedYaw = smootherYaw->update(desiredYaw, desiredYawVel);
01059 }
01060 else
01061 {
01062 smoothedPitch = smootherPitch->reset(desiredPitch, desiredPitchVel);
01063 smoothedYaw = smootherYaw->reset(desiredYaw, desiredYawVel);
01064 }
01065
01066 wrist->applyLimits(smoothedPitch, smoothedYaw);
01067 desiredSlider = wrist->getSliderFromAngle(Vector2d(smoothedPitch, smoothedYaw));
01068
01069 desiredQ1 = desiredSlider(0);
01070 desiredQ2 = desiredSlider(1);
01071 commandedStateMsg.desiredPosition[0] = desiredPitch;
01072 commandedStateMsg.desiredPosition[1] = desiredYaw;
01073 commandedStateMsg.desiredPositionVelocityLimit[0] = desiredPitchVel;
01074 commandedStateMsg.desiredPositionVelocityLimit[1] = desiredYawVel;
01075 }
01076 catch (std::runtime_error)
01077 {
01079 NasaCommonLogging::Logger::getCategory("gov.nasa.robonet.JointCommandWrist") << log4cpp::Priority::ERROR << "Kinematics failed on (" << desiredPitch << "," << desiredYaw << ") command to joints " << roboDynJoints[0] << ", " << roboDynJoints[1];
01080 control.controlMode.state = r2_msgs::JointControlMode::PARK;
01081 }
01082 }
01083 }
01084
01085 double motcom1 = 0;
01086 double motcom2 = 0;
01087
01089 if (control.controlMode.state == r2_msgs::JointControlMode::DRIVE)
01090 {
01091 if (control.commandMode.state == r2_msgs::JointControlCommandMode::MOTCOM)
01092 {
01093 motcom1 = desiredQ1;
01094 motcom2 = desiredQ2;
01095 }
01096 else if (wrist->isCalibrated)
01097 {
01098 motcom1 = q1Controller->update(desiredQ1, (double)filteredSlider(0), (double)sliderVel(0), busVoltage, sliderVelCommand(0));
01099 motcom2 = q2Controller->update(desiredQ2, (double)filteredSlider(1), (double)sliderVel(1), busVoltage, sliderVelCommand(1));
01100 }
01101 }
01102
01103 io.setInt16(desiredMotComThumbCommandElement, motcom1);
01104 io.setInt16(desiredMotComLittleCommandElement, motcom2);
01105 }
01106
01107 r2_msgs::JointCapability JointCommandWrist::getCapability()
01108 {
01109 double up, uy, lp, ly;
01110 wrist->getLimits(ang(0), ang(1), up, lp, uy, ly);
01111 jointCapabilityMsg.positionLimitMax[0] = up;
01112 jointCapabilityMsg.positionLimitMax[1] = uy;
01113 jointCapabilityMsg.positionLimitMin[0] = lp;
01114 jointCapabilityMsg.positionLimitMin[1] = ly;
01115
01117
01118 return jointCapabilityMsg;
01119 }