55 #include "rnr/rnrconfig.h" 57 #include "rnr/appkit/Xml.h" 73 const string &strSearchPath,
74 const string &strXmlFileName,
77 vector<string> vecPath;
83 split(strSearchPath,
':', vecPath);
85 bFoundInstance =
false;
88 for(i=0; i<vecPath.size(); ++i)
90 fqname = vecPath[i] +
'/' + strXmlFileName;
91 if( access(fqname.c_str(), F_OK) == 0 )
93 LOGDIAG3(
"Loading tune XML file: %s.", fqname.c_str());
95 bFoundInstance =
true;
97 if( (rc = Xml::loadFile(fqname)) < 0 )
99 LOGERROR(
"Parse of tune parameters from XML file %s failed.",
105 rc = setTunesFromDOM(tunes);
110 LOGDIAG2(
"Tuning parameters from XML file %s loaded.",
121 if( !bFoundInstance )
123 LOGDIAG2(
"Optional XML file %s not found - ignoring.",
124 strXmlFileName.c_str());
130 int HekXmlTune::loadFile(
const std::string &strXmlFileName)
135 if( access(strXmlFileName.c_str(), F_OK) < 0 )
137 LOGDIAG2(
"Optional XML file %s does not exist - ignoring.",
138 strXmlFileName.c_str());
143 else if( (rc = Xml::loadFile(strXmlFileName)) < 0 )
145 LOGERROR(
"Parse of tune parameters from XML file %s failed - ignoring.",
146 strXmlFileName.c_str());
159 int HekXmlTune::createTemplateFile(
const string &strXmlFileName)
163 if( strXmlFileName.empty() )
165 setErrorMsg(
"No file name.");
166 LOGERROR(
"%s", m_bufErrMsg);
167 return -HEK_ECODE_XML;
170 m_strXmlFileName = strXmlFileName;
173 if( (fp = fopen(m_strXmlFileName.c_str(),
"w+")) == NULL )
175 setErrorMsg(
"%s: %s(errno=%d).",
176 m_strXmlFileName.c_str(), strerror(errno), errno);
177 LOGERROR(
"%s", m_bufErrMsg);
178 return -HEK_ECODE_XML;
187 fprintf(fp,
" <!-- RoadNarrows Hekateros Tuning Configuration -->\n");
188 fprintf(fp,
"%s", m_strXmlHead.c_str());
193 fprintf(fp,
" <!-- Hekateros tuning -->\n");
194 fprintf(fp,
" <%s>\n", m_strMajElemTuning.c_str());
196 fprintf(fp,
" <!-- global tunes -->\n");
197 fprintf(fp,
" <%s>\n", m_strSecElemGlobal.c_str());
198 fprintf(fp,
" <%s>HZ</%s>\n",
199 m_strElemKinHz.c_str(), m_strElemKinHz.c_str());
200 fprintf(fp,
" <%s>OFFSET_PCT</%s>\n",
201 m_strElemClearTorqueOff.c_str(), m_strElemClearTorqueOff.c_str());
202 fprintf(fp,
" <%s>DERATE_PCT</%s>\n",
203 m_strElemVelDerate.c_str(), m_strElemVelDerate.c_str());
204 fprintf(fp,
" <%s>\n", m_strSubSecElemTraj.c_str());
205 fprintf(fp,
" <%s>NORM</%s>\n",
206 m_strElemTrajNorm.c_str(), m_strElemTrajNorm.c_str());
207 fprintf(fp,
" <%s>E_DEG</%s>\n",
208 m_strElemTrajEpsilon.c_str(), m_strElemTrajEpsilon.c_str());
209 fprintf(fp,
" </%s>\n", m_strSubSecElemTraj.c_str());
210 fprintf(fp,
" </%s>\n", m_strSecElemGlobal.c_str());
212 fprintf(fp,
" <!-- joint tunes -->\n");
213 fprintf(fp,
" <%s %s=\"JOINT_NAME\">\n",
214 m_strSecElemJoint.c_str(), m_strAttrJointId.c_str());
215 fprintf(fp,
" <%s>POS_TOL_DEG</%s>\n",
216 m_strElemTolPos.c_str(), m_strElemTolPos.c_str());
217 fprintf(fp,
" <%s>VEL_TOL_DEG_PER_SEC</%s>\n",
218 m_strElemTolVel.c_str(), m_strElemTolVel.c_str());
219 fprintf(fp,
" <%s>OVER_TORQUE_TH_PCT</%s>\n",
220 m_strElemOverTorqueTh.c_str(), m_strElemOverTorqueTh.c_str());
221 fprintf(fp,
" <%s>\n", m_strSubSecElemPid.c_str());
222 fprintf(fp,
" <%s>FPN</%s>\n",
223 m_strElemPidKp.c_str(), m_strElemPidKp.c_str());
224 fprintf(fp,
" <%s>FPN</%s>\n",
225 m_strElemPidKi.c_str(), m_strElemPidKi.c_str());
226 fprintf(fp,
" <%s>FPN</%s>\n",
227 m_strElemPidKd.c_str(), m_strElemPidKd.c_str());
228 fprintf(fp,
" <%s>FPN</%s>\n",
229 m_strElemPidMaxDeltaV.c_str(), m_strElemPidMaxDeltaV.c_str());
230 fprintf(fp,
" </%s>\n", m_strSubSecElemPid.c_str());
231 fprintf(fp,
" </%s>\n", m_strSecElemJoint.c_str());
233 fprintf(fp,
" </%s>\n\n", m_strMajElemTuning.c_str());
238 fprintf(fp,
"%s", m_strXmlTail.c_str());
242 LOGDIAG3(
"Created file %s.", m_strXmlFileName.c_str());
249 TiXmlElement *pElem1, *pElem2;
254 if( m_pElemRoot == NULL )
256 setErrorMsg(
"Missing DOM and/or <%s> root element missing.",
257 m_strRootElemName.c_str());
258 LOGERROR(
"%s", m_bufErrMsg);
259 return -HEK_ECODE_XML;
263 for(pElem1 = m_pElemRoot->FirstChildElement(), rc = HEK_OK;
264 (pElem1 != NULL) && (rc == HEK_OK);
265 pElem1 = pElem1->NextSiblingElement())
268 if( (sValue = pElem1->Value()) == NULL )
276 else if( !strcasecmp(sValue, m_strMajElemTuning.c_str()) )
279 for(pElem2 = pElem1->FirstChildElement();
280 (pElem2 != NULL) && (rc == HEK_OK);
281 pElem2 = pElem2->NextSiblingElement())
284 if( (sValue = pElem2->Value()) == NULL )
290 else if( !strcasecmp(sValue, m_strSecElemGlobal.c_str()) )
292 rc = setGlobalTunes(pElem2, tunes);
296 else if( !strcasecmp(sValue, m_strSecElemJoint.c_str()) )
298 rc = setJointTunes(pElem2, tunes);
304 warnUnknownElem(sValue);
313 int HekXmlTune::setDOMFromHekTunes(
const HekTunes &tunes)
316 return -HEK_ECODE_GEN;
319 int HekXmlTune::setGlobalTunes(TiXmlElement *pElemSec,
HekTunes &tunes)
328 for(pElem = pElemSec->FirstChildElement(), rc = HEK_OK;
329 (pElem != NULL) && (rc == HEK_OK);
330 pElem = pElem->NextSiblingElement())
333 if( (sValue = pElem->Value()) == NULL )
339 else if( !strcasecmp(sValue, m_strElemKinHz.c_str()) )
341 rc = strToDoubleWithMinimum(m_strElemKinHz, elemText(pElem),
346 else if( !strcasecmp(sValue, m_strElemClearTorqueOff.c_str()) )
348 rc = strToDoubleWithinRange(m_strElemClearTorqueOff, elemText(pElem),
349 HekTuneClearTorqueOffsetMin, HekTuneClearTorqueOffsetMax,
360 else if( !strcasecmp(sValue, m_strElemVelDerate.c_str()) )
362 rc = strToDoubleWithinRange(m_strElemVelDerate, elemText(pElem),
363 HekTuneVelDerateMin, HekTuneVelDerateMax,
374 else if( !strcasecmp(sValue, m_strSubSecElemTraj.c_str()) )
376 rc = setGlobalTrajTunes(pElem, tunes);
382 warnUnknownElem(sValue);
388 LOGDIAG3(
"%s: Hekateros global tune parameters set.",
389 m_strXmlFileName.c_str());
395 int HekXmlTune::setJointTunes(TiXmlElement *pElemSec,
HekTunes &tunes)
403 strJointName = elemAttr(pElemSec, m_strAttrJointId);
405 if( strJointName.empty() )
407 setErrorMsg(
"%s: No %s attribute of <%s> found.",
408 m_strXmlFileName.c_str(),
409 m_strAttrJointId.c_str(),
410 m_strSecElemJoint.c_str());
411 LOGERROR(
"%s", m_bufErrMsg);
412 return -HEK_ECODE_XML;
424 for(pElem = pElemSec->FirstChildElement(), rc = HEK_OK;
425 (pElem != NULL) && (rc == HEK_OK);
426 pElem = pElem->NextSiblingElement())
429 if( (sValue = pElem->Value()) == NULL )
435 else if( !strcasecmp(sValue, m_strElemTolPos.c_str()) )
437 rc = strToDoubleWithMinimum(m_strElemTolPos, elemText(pElem),
449 else if( !strcasecmp(sValue, m_strElemTolVel.c_str()) )
451 rc = strToDoubleWithMinimum(m_strElemTolVel, elemText(pElem),
463 else if( !strcasecmp(sValue, m_strElemOverTorqueTh.c_str()) )
465 rc = strToDoubleWithinRange(m_strElemOverTorqueTh, elemText(pElem),
466 HekTuneOverTorqueThMin, HekTuneOverTorqueThMax,
477 else if( !strcasecmp(sValue, m_strSubSecElemPid.c_str()) )
479 rc = setJointPidTunes(strJointName, pElem, tunesJoint);
485 warnUnknownElem(sValue);
494 LOGDIAG3(
"%s: Hekateros joint %s tune parameters set.",
495 m_strXmlFileName.c_str(), strJointName.c_str());
501 int HekXmlTune::setGlobalTrajTunes(TiXmlElement *pElemSubSec,
HekTunes &tunes)
510 for(pElem = pElemSubSec->FirstChildElement(), rc = HEK_OK;
511 (pElem != NULL) && (rc == HEK_OK);
512 pElem = pElem->NextSiblingElement())
515 if( (sValue = pElem->Value()) == NULL )
521 else if( !strcasecmp(sValue, m_strElemTrajNorm.c_str()) )
523 strToNorm(m_strElemTrajNorm, elemText(pElem), tunes.
m_eTrajNorm);
527 else if( !strcasecmp(sValue, m_strElemTrajEpsilon.c_str()) )
529 rc = strToDoubleWithMinimum(m_strElemTrajEpsilon, elemText(pElem),
542 warnUnknownElem(sValue);
548 LOGDIAG3(
"%s: Hekateros global trajectory tune parameters set.",
549 m_strXmlFileName.c_str());
555 int HekXmlTune::setJointPidTunes(
const string &strJointName,
556 TiXmlElement *pElemSubSec,
566 for(pElem = pElemSubSec->FirstChildElement(), rc = HEK_OK;
567 (pElem != NULL) && (rc == HEK_OK);
568 pElem = pElem->NextSiblingElement())
571 if( (sValue = pElem->Value()) == NULL )
577 else if( !strcasecmp(sValue, m_strElemPidKp.c_str()) )
579 rc = strToDoubleWithMinimum(m_strElemPidKp, elemText(pElem),
580 HekTunePidKMin, tunesJoint.
m_fPidKp);
584 else if( !strcasecmp(sValue, m_strElemPidKi.c_str()) )
586 rc = strToDoubleWithMinimum(m_strElemPidKi, elemText(pElem),
587 HekTunePidKMin, tunesJoint.
m_fPidKi);
591 else if( !strcasecmp(sValue, m_strElemPidKd.c_str()) )
593 rc = strToDoubleWithMinimum(m_strElemPidKd, elemText(pElem),
594 HekTunePidKMin, tunesJoint.
m_fPidKd);
598 else if( !strcasecmp(sValue, m_strElemPidMaxDeltaV.c_str()) )
600 rc = strToDoubleWithMinimum(m_strElemPidMaxDeltaV, elemText(pElem),
601 HekTunePidDeltaVNoMax,
614 warnUnknownElem(sValue);
620 LOGDIAG3(
"%s: Hekateros joint %s PID tune parameters set.",
621 m_strXmlFileName.c_str(), strJointName.c_str());
627 int HekXmlTune::strToDoubleWithMinimum(
const string &strElem,
628 const string &strText,
634 if( !strText.empty() )
636 if( (rc = strToDouble(strText, fVal)) < 0 )
638 setErrorMsg(
"%s: Element <%s> text \"%s\" not a FPN.",
639 m_strXmlFileName.c_str(), strElem.c_str(), strText.c_str());
640 LOGERROR(
"%s", m_bufErrMsg);
644 else if( fVal < fMin )
646 setErrorMsg(
"%s: Element <%s> value %lf < than minimum of %lf.",
647 m_strXmlFileName.c_str(), strElem.c_str(), fVal, fMin);
648 LOGWARN(
"%s", m_bufErrMsg);
656 int HekXmlTune::strToDoubleWithinRange(
const string &strElem,
657 const string &strText,
664 if( !strText.empty() )
666 if( (rc = strToDouble(strText, fVal)) < 0 )
668 setErrorMsg(
"%s: Element <%s> text \"%s\" not a FPN.",
669 m_strXmlFileName.c_str(), strElem.c_str(), strText.c_str());
670 LOGERROR(
"%s", m_bufErrMsg);
674 else if( fVal < fMin )
676 setErrorMsg(
"%s: Element <%s> value %lf < than minimum of %lf.",
677 m_strXmlFileName.c_str(), strElem.c_str(), fVal, fMin);
678 LOGWARN(
"%s", m_bufErrMsg);
682 else if( fVal > fMax )
684 setErrorMsg(
"%s: Element <%s> value %lf > than maximum of %lf.",
685 m_strXmlFileName.c_str(), strElem.c_str(), fVal, fMax);
686 LOGWARN(
"%s", m_bufErrMsg);
694 int HekXmlTune::strToNorm(
const string &strElem,
695 const string &strText,
698 if( strText.empty() )
702 else if( !strcasecmp(strText.c_str(),
"L1") )
707 else if( !strcasecmp(strText.c_str(),
"L2") )
712 else if( !strcasecmp(strText.c_str(),
"Linf") )
719 setErrorMsg(
"%s: Element <%s> text \"%s\" not a recognized norm.",
720 m_strXmlFileName.c_str(), strElem.c_str(), strText.c_str());
721 LOGERROR(
"%s", m_bufErrMsg);
722 return -HEK_ECODE_XML;
double m_fPidKi
position and velocity PID integral constant
double m_fPidKp
position and velocity PID proportional const
double m_fTolVel
velocitiy tolerance (radians/second)
double m_fVelDerate
velocity derate (fraction)
Hekateros tuning per joint data class.
double m_fTrajEpsilon
trajectory epsilon distance (radians)
Hekateros tuning data class.
double m_fOverTorqueTh
over torque conditon threshold (fraction)
double m_fKinematicsHz
kinematic thread rate (hertz)
double m_fPidKd
position and velocity PID derivative constant
double m_fPidMaxDeltaV
max output delta v (radians/second)
std::vector< std::string > & split(const std::string &s, char delim, std::vector< std::string > &elems)
Split string at the delimiter character.
HekNorm m_eTrajNorm
trajectory distanct norm
Top-level package include file.
double degToRad(double d)
Convert degrees to radians.
MapJointTunes m_mapJointTunes
per joint tuning
Hekateros common utilities.
double m_fClearTorqueOffset
clear over torque condition offset (frac)
The <b><i>Hekateros</i></b> namespace encapsulates all <b><i>Hekateros</i></b> related constructs...
<b><i>Hekateros</i></b> XML tuning class interface.
double m_fTolPos
position tolerance (radians)