56 #include "rnr/rnrconfig.h" 80 static u32_t MoveAccel = 100000;
81 static u32_t StopDecel = 100000;
83 static int SpeedReallyZero = 5;
89 LaeKinematics::LaeKinematics()
94 for(nCtlr=0; nCtlr<LaeNumMotorCtlrs; ++nCtlr)
96 m_pMotorCtlr[nCtlr] = NULL;
102 pthread_mutex_init(&m_mutex, NULL);
104 m_fnEnableMotorCtlrs = NULL;
106 m_bIsEnabled =
false;
107 m_bAreMotorsPowered =
false;
111 LaeKinematics::~LaeKinematics()
115 if( m_pAction != NULL )
122 for(nCtlr=0; nCtlr<LaeNumMotorCtlrs; ++nCtlr)
124 if( m_pMotorCtlr[nCtlr] != NULL )
126 delete m_pMotorCtlr[nCtlr];
127 m_pMotorCtlr[nCtlr] = NULL;
133 pthread_mutex_destroy(&m_mutex);
141 int LaeKinematics::open(
const std::string &strDevMotorCtlrs,
143 int (*fnEnable)(
void *,
bool),
149 m_fnEnableMotorCtlrs = fnEnable;
150 m_pEnableArg = pEnableArg;
151 m_bIsEnabled =
false;
158 LOGERROR(
"Failed to enable power to motor controllers.");
159 return -LAE_ECODE_IO;
162 #ifdef LAE_DEPRECATED 164 if( m_csMotorCtlrs.open(LaeGpioMotorCtlrCs) < 0 )
166 LOGSYSERROR(
"Failed to open motor controller chip select on GPIO pin %d.",
168 return -LAE_ECODE_MOT_CTLR;
171 LOGDIAG2(
"Opened motor controllers chip select signal on GPIO %d.",
173 #endif // LAE_DEPRECATED 179 if( m_commMotorCtlrs.open(strDevName, nBaudRate) < 0 )
181 LOGERROR(
"%s: Failed to open motor controller port at %d baud.",
182 strDevName.c_str(), nBaudRate);
183 return -LAE_ECODE_MOT_CTLR;
186 LOGDIAG3(
"Open motor controllers serial communication on %s@%d.",
187 strDevName.c_str(), nBaudRate);
192 nCtlr = LaeMotorCtlrIdFront;
193 m_pMotorCtlr[nCtlr] =
194 new RoboClaw(m_commMotorCtlrs, LaeMotorCtlrAddrFront, LaeKeyFront);
195 m_pMotorCtlr[nCtlr]->setMotorDir(LaeMotorLeft, LaeMotorDirNormal);
196 m_pMotorCtlr[nCtlr]->setMotorDir(LaeMotorRight, LaeMotorDirNormal);
201 nCtlr = LaeMotorCtlrIdRear;
202 m_pMotorCtlr[nCtlr] =
203 new RoboClaw(m_commMotorCtlrs, LaeMotorCtlrAddrRear, LaeKeyRear);
204 m_pMotorCtlr[nCtlr]->setMotorDir(LaeMotorLeft, LaeMotorDirNormal);
205 m_pMotorCtlr[nCtlr]->setMotorDir(LaeMotorRight, LaeMotorDirNormal);
207 m_bAreMotorsPowered =
false;
210 RtDb.m_robotstatus.m_bAreMotorsPowered = m_bAreMotorsPowered;
211 RtDb.m_robotstatus.m_bInMotion = m_bIsStopped?
false:
true;
213 LOGDIAG2(
"Created front and rear motor controllers on %s@%d.",
214 strDevName.c_str(), nBaudRate);
221 int LaeKinematics::close()
223 if( m_pAction != NULL )
225 m_pAction->terminate();
228 #ifdef LAE_DEPRECATED 229 m_csMotorCtlrs.close();
230 #endif // LAE_DEPRECATED 232 m_commMotorCtlrs.close();
238 LOGWARN(
"Failed to disable power to motor controllers.");
241 LOGDIAG2(
"Closed motor controllers serial communication.");
246 void LaeKinematics::enableMotorCtlrs()
250 #ifdef LAE_DEPRECATED 251 m_bIsEnabled = m_power.enable();
253 #endif // LAE_DEPRECATED 258 if( m_fnEnableMotorCtlrs != NULL )
260 if( (rc = m_fnEnableMotorCtlrs(m_pEnableArg,
true)) == LAE_OK )
263 LOGDIAG2(
"Enabled power to motor controllers.");
276 void LaeKinematics::disableMotorCtlrs()
280 #ifdef LAE_DEPRECATED 281 m_bIsEnabled = m_power.disable();
283 #endif // LAE_DEPRECATED 288 if( m_fnEnableMotorCtlrs != NULL )
290 if( (rc = m_fnEnableMotorCtlrs(m_pEnableArg,
false)) == LAE_OK )
292 m_bIsEnabled =
false;
293 m_bAreMotorsPowered =
false;
296 RtDb.m_robotstatus.m_bAreMotorsPowered = m_bAreMotorsPowered;
297 RtDb.m_robotstatus.m_bInMotion = m_bIsStopped?
false:
true;
299 LOGDIAG2(
"Disabled power to motor controllers.");
309 m_bIsEnabled =
false;
313 void LaeKinematics::resyncComm()
315 LOGDIAG3(
"Resynchronizing motor controller serial communication.");
317 m_bIsEnabled =
false;
331 int LaeKinematics::configure(
const LaeDesc &desc)
333 LaeDesc::MapDescPowertrain::const_iterator iter;
354 m_kinPowertrains[train.
m_strName] = train;
362 LOGDIAG2(
"Configured motor controllers from robot description.");
367 int LaeKinematics::configure(
const LaeTunes &tunes)
372 for(nCtlr = 0; nCtlr < LaeNumMotorCtlrs; ++nCtlr)
374 if( (rc = configureMotorController(tunes, nCtlr)) != LAE_OK )
380 m_kinPlatform.configure(tunes);
384 LOGDIAG2(
"Tuned motor controllers.");
390 int LaeKinematics::configureMotorController(
const LaeTunes &tunes,
int nCtlr)
405 if( (rc = configMotorCtlrBatteryCutoffs(tunes, nCtlr, bNvmSave)) != LAE_OK )
411 if( (rc = configMotorCtlrLogicCutoffs(tunes, nCtlr, bNvmSave)) != LAE_OK )
417 if( (rc = configMotorCtlrEncoderModes(tunes, nCtlr, bNvmSave)) != LAE_OK )
425 if( (rc = configurePtp(tunes, nCtlr, bNvmSave)) != LAE_OK )
436 saveConfigToNvm(nCtlr);
442 resetMotorCtlrEncoders(nCtlr);
447 int LaeKinematics::configMotorCtlrBatteryCutoffs(
const LaeTunes &tunes,
451 string strTag = LaeDesc::prettyMotorCtlrName(nCtlr,
452 m_pMotorCtlr[nCtlr]->getAddress());
455 double fMinMin, fMaxMax;
463 LOGDIAG3(
"%s: Verifying main battery cutoff voltages...", strTag.c_str());
468 rc = m_pMotorCtlr[nCtlr]->cmdReadMainBattCutoffs(fMin, fMax);
472 LOGWARN(
"%s: Failed to read main battery cutoff voltages.", strTag.c_str());
476 LOGDIAG3(
" Current settings: [%.1lf, %.1lf]", fMin, fMax);
479 m_pMotorCtlr[nCtlr]->getMainBattCutoffRange(fMinMin, fMaxMax);
485 if( (fMin != fMinMin) || (fMax != fMaxMax) )
487 rc = m_pMotorCtlr[nCtlr]->cmdSetMainBattCutoffs(fMinMin, fMaxMax);
491 LOGWARN(
"%s: Failed to set main battery cutoff voltages to " 493 strTag.c_str(), fMinMin, fMaxMax);
497 LOGDIAG3(
" Changed settings: [%.1lf, %.1lf]", fMinMin, fMaxMax);
512 int LaeKinematics::configMotorCtlrLogicCutoffs(
const LaeTunes &tunes,
516 string strTag = LaeDesc::prettyMotorCtlrName(nCtlr,
517 m_pMotorCtlr[nCtlr]->getAddress());
520 double fMinMin, fMaxMax;
531 LOGDIAG3(
"%s: Verifying logic cutoff voltages...", strTag.c_str());
536 rc = m_pMotorCtlr[nCtlr]->cmdReadLogicCutoffs(fMin, fMax);
540 LOGWARN(
"%s: Failed to read logic cutoff voltages.", strTag.c_str());
544 LOGDIAG3(
" Current settings: [%.1lf, %.1lf]", fMin, fMax);
547 m_pMotorCtlr[nCtlr]->getLogicCutoffRange(fMinMin, fMaxMax);
553 if( (fMin != fMinMin) || (fMax != fMaxMax) )
555 rc = m_pMotorCtlr[nCtlr]->cmdSetLogicCutoffs(fMinMin, fMaxMax);
559 LOGWARN(
"%s: Failed to set logic cutoff voltages to [%.1lf, %.1lf].",
560 strTag.c_str(), fMinMin, fMaxMax);
564 LOGDIAG3(
" Changed settings: [%.1lf, %.1lf]", fMinMin, fMaxMax);
579 int LaeKinematics::configMotorCtlrEncoderModes(
const LaeTunes &tunes,
583 string strTag = LaeDesc::prettyMotorCtlrName(nCtlr,
584 m_pMotorCtlr[nCtlr]->getAddress());
586 byte_t byMode1, byMode2;
594 LOGDIAG3(
"%s: Verifying motor quadrature encoder modes...", strTag.c_str());
599 rc = m_pMotorCtlr[nCtlr]->cmdReadEncoderMode(byMode1, byMode2);
603 LOGERROR(
"%s: Failed to read motor encoder modes.", strTag.c_str());
604 return -LAE_ECODE_MOT_CTLR;
607 LOGDIAG3(
" Current settings: [0x%02x, 0x%02x]", byMode1, byMode2);
613 if( (byMode1 != ParamEncModeQuad) || (byMode2 != ParamEncModeQuad) )
615 rc = m_pMotorCtlr[nCtlr]->cmdSetEncoderMode2(ParamEncModeQuad,
620 LOGERROR(
"%s: Failed to set motor encoders to quadrature encoding " 622 strTag.c_str(), ParamEncModeQuad, ParamEncModeQuad);
623 return -LAE_ECODE_MOT_CTLR;
626 LOGDIAG3(
" Changed settings: [0x%02x, 0x%02x]",
627 ParamEncModeQuad, ParamEncModeQuad);
643 int LaeKinematics::resetMotorCtlrEncoders(
int nCtlr)
645 string strTag = LaeDesc::prettyMotorCtlrName(nCtlr,
646 m_pMotorCtlr[nCtlr]->getAddress());
650 rc = m_pMotorCtlr[nCtlr]->cmdResetQEncoders();
654 LOGDIAG3(
"%s: Encoders reset.", strTag.c_str());
659 LOGWARN(
"%s: Failed to reset encoders.", strTag.c_str());
660 return -LAE_ECODE_MOT_CTLR;
664 int LaeKinematics::configurePtp(
const LaeTunes &tunes,
668 LaeMapPowertrain::iterator pos;
673 string strKey = m_pMotorCtlr[nCtlr]->getNameId();
675 for(nMotor = LaeMotorLeft; nMotor < LaeNumMotorsPerCtlr; ++nMotor)
677 strKey = LaePowertrain::toKey(nCtlr, nMotor);
682 if( (pos = m_kinPowertrains.find(strKey)) == m_kinPowertrains.end() )
684 LOGWARN(
"Cannot find powertrain %s - ignoring.", strKey.c_str());
689 pos->second.configure(tunes);
692 if( (rc = configMotorVelocityPid(tunes, pos->second, bNvmSave)) != LAE_OK )
698 if( (rc = configMotorMaxAmpLimit(tunes, pos->second, bNvmSave)) != LAE_OK )
711 int LaeKinematics::configMotorVelocityPid(
const LaeTunes &tunes,
719 byte_t addr = m_pMotorCtlr[nCtlrId]->getAddress();
720 string strTag = LaeDesc::prettyMotorName(nCtlrId, addr, nMotorId);
722 u32_t uKp, uKi, uKd, uQpps;
723 double fTuneKp, fTuneKi, fTuneKd;
724 u32_t uTuneKp, uTuneKi, uTuneKd, uTuneQpps;
731 LOGDIAG3(
"%s: Verifying velocity PID parameters...", strTag.c_str());
736 rc = m_pMotorCtlr[nCtlrId]->cmdReadVelocityPidConst(nMotor,
737 uKp, uKi, uKd, uQpps);
741 LOGWARN(
"%s: Failed to read velocity PID constants.", strTag.c_str());
745 fTuneKp = (double)uKp / (
double)ParamVelPidCvt;
746 fTuneKi = (double)uKi / (
double)ParamVelPidCvt;
747 fTuneKd = (double)uKd / (
double)ParamVelPidCvt;
749 LOGDIAG3(
" Current settings: " 750 "Kp=%lf (raw=0x%08x), Ki=%lf (raw=0x%08x), Kd=%lf (raw=0x%08x), Qpps=%u.",
751 fTuneKp, uKp, fTuneKi, uKi, fTuneKd, uKd, uQpps);
757 uTuneKp = (u32_t)(fTuneKp * (
double)ParamVelPidCvt);
758 uTuneKi = (u32_t)(fTuneKi * (
double)ParamVelPidCvt);
759 uTuneKd = (u32_t)(fTuneKd * (
double)ParamVelPidCvt);
766 if( (uKp != uTuneKp) || (uKi != uTuneKi) || (uKd != uTuneKd) ||
767 (uQpps != uTuneQpps) )
769 rc = m_pMotorCtlr[nCtlrId]->cmdSetVelocityPidConst(nMotor,
770 uTuneKp, uTuneKi, uTuneKd, uTuneQpps);
774 LOGWARN(
"%s: Failed to set velocity PID constants.", strTag.c_str());
778 LOGDIAG3(
" Changed settings: " 779 "Kp=%lf (raw=0x%08x), Ki=%lf (raw=0x%08x), Kd=%lf (raw=0x%08x), " 781 fTuneKp, uTuneKp, fTuneKi, uTuneKi, fTuneKd, uTuneKd, uTuneQpps);
798 int LaeKinematics::configMotorMaxAmpLimit(
const LaeTunes &tunes,
806 byte_t addr = m_pMotorCtlr[nCtlrId]->getAddress();
807 string strTag = LaeDesc::prettyMotorName(nCtlrId, addr, nMotorId);
809 double fCurMaxAmps, fMaxAmps;
818 LOGDIAG3(
"%s: Verifying maximum amp limit parameter...", strTag.c_str());
823 rc = m_pMotorCtlr[nCtlrId]->cmdReadMotorMaxCurrentLimit(nMotor, fCurMaxAmps);
827 LOGERROR(
"%s: Failed to read maximum current limit.", strTag.c_str());
828 return -LAE_ECODE_MOT_CTLR;
831 LOGDIAG3(
" Current settings: %.2lf amps.", fCurMaxAmps);
833 if( RtDb.m_product.m_uProdHwVer ==
LAE_VERSION(2, 0, 0) )
835 fMaxAmps = LaeMotorMaxAmps_2_0 - 0.05;
839 fMaxAmps = LaeMotorMaxAmps_2_1 - 0.05;
846 if( fCurMaxAmps != fMaxAmps )
848 rc = m_pMotorCtlr[nCtlrId]->cmdSetMotorMaxCurrentLimit(nMotor, fMaxAmps);
852 LOGERROR(
"%s: Failed to set maximum current limit to %.2lf.",
853 strTag.c_str(), fMaxAmps);
854 return -LAE_ECODE_MOT_CTLR;
858 LOGDIAG3(
" Changed settings: %.2lf amps.", fMaxAmps);
874 int LaeKinematics::saveConfigToNvm(
int nCtlrId)
876 string strTag = LaeDesc::prettyMotorCtlrName(nCtlrId,
877 m_pMotorCtlr[nCtlrId]->getAddress());
881 LOGDIAG3(
"%s: Saving new values to EEPROM.", strTag.c_str());
883 rc = m_pMotorCtlr[nCtlrId]->cmdWriteSettingsToEEPROM();
891 LOGWARN(
"%s: Failed to write settings to EEPROM.", strTag.c_str());
899 LaeMapPowertrain::iterator iter;
901 LOGDIAG2(
"Reloading motor controller tuning parameters...");
903 for(iter = m_kinPowertrains.begin(); iter != m_kinPowertrains.end(); ++iter)
905 iter->second.reload(tunes);
908 m_kinPlatform.reload(tunes);
918 RoboClaw *LaeKinematics::getMotorCtlr(
const int nMotorCtlrId)
920 if( (nMotorCtlrId >= 0) && (nMotorCtlrId < LaeNumMotorCtlrs) )
922 return m_pMotorCtlr[nMotorCtlrId];
930 LaePowertrain *LaeKinematics::getPowertrain(
const string &strName)
932 if( m_kinPowertrains.find(strName) != m_kinPowertrains.end() )
934 return &m_kinPowertrains[strName];
944 std::string strName = LaePowertrain::toKey(nCtlr, nMotor);
946 if( m_kinPowertrains.find(strName) != m_kinPowertrains.end() )
948 return &m_kinPowertrains[strName];
958 std::string strName = LaePowertrain::toKey(nMotorId);
960 if( m_kinPowertrains.find(strName) != m_kinPowertrains.end() )
962 return &m_kinPowertrains[strName];
970 int LaeKinematics::getPowertrainState(
const std::string &strName,
973 LaeMapPowertrain::iterator pos;
975 if( (pos = m_kinPowertrains.find(strName)) != m_kinPowertrains.end() )
977 jointState = pos->second.m_state;
982 return -LAE_ECODE_BAD_VAL;
986 bool LaeKinematics::isStopped()
989 LaeMapPowertrain::iterator iter;
991 for(iter = m_kinPowertrains.begin(), bIsStopped =
true;
992 (iter != m_kinPowertrains.end()) && bIsStopped;
995 if(
iabs(iter->second.m_state.m_nSpeed) > SpeedReallyZero )
1001 m_bIsStopped = bIsStopped;
1002 RtDb.m_robotstatus.m_bInMotion = m_bIsStopped?
false:
true;
1004 return m_bIsStopped;
1007 bool LaeKinematics::isStopped(
const std::string &strName)
1009 LaeMapPowertrain::iterator pos;
1011 if( (pos = m_kinPowertrains.find(strName)) != m_kinPowertrains.end() )
1013 return iabs(pos->second.m_state.m_nSpeed) <= SpeedReallyZero;
1026 int LaeKinematics::resetOdometers()
1039 m_pAction->terminate();
1041 for(nCtlr = 0; nCtlr < LaeNumMotorCtlrs; ++nCtlr)
1043 if( m_pMotorCtlr[nCtlr]->cmdResetQEncoders() == OK )
1045 for(nMotor = 0; nMotor < LaeNumMotorsPerCtlr; ++nMotor)
1047 if( (pTrain = getPowertrain(nCtlr, nMotor)) != NULL )
1056 m_kinPlatform.resetOdometer();
1064 void LaeKinematics::estop()
1072 m_pAction->terminate();
1074 for(nCtlr = 0; nCtlr < LaeNumMotorCtlrs; ++nCtlr)
1076 m_pMotorCtlr[nCtlr]->cmdEStop();
1079 disableMotorCtlrs();
1085 void LaeKinematics::resetEStop()
1094 int LaeKinematics::release()
1103 m_pAction->terminate();
1105 for(nCtlr = 0; nCtlr < LaeNumMotorCtlrs; ++nCtlr)
1107 m_pMotorCtlr[nCtlr]->cmdDutyDrive2(0.0, 0.0);
1110 m_bAreMotorsPowered =
false;
1111 RtDb.m_robotstatus.m_bAreMotorsPowered = m_bAreMotorsPowered;
1117 rc = -LAE_ECODE_BAD_OP;
1125 int LaeKinematics::stop()
1134 m_pAction->terminate();
1136 for(nCtlr = 0; nCtlr < LaeNumMotorCtlrs; ++nCtlr)
1139 m_pMotorCtlr[nCtlr]->cmdStopWithDecel(StopDecel);
1142 m_bAreMotorsPowered =
true;
1143 RtDb.m_robotstatus.m_bAreMotorsPowered = m_bAreMotorsPowered;
1149 rc = -LAE_ECODE_BAD_OP;
1157 int LaeKinematics::stop(
const vector<string> &vecNames)
1159 vector<string>::const_iterator iter;
1161 LaeMapPowertrain::iterator pos;
1173 m_pAction->terminate();
1175 for(iter = vecNames.begin(); iter != vecNames.end(); ++iter)
1177 if( (pos = m_kinPowertrains.find(*iter)) != m_kinPowertrains.end() )
1179 nCtlr = pos->second.getMotorCtlrId();
1180 nMotor = pos->second.getMotorIndex();
1183 if( m_pMotorCtlr[nCtlr]->cmdStopWithDecel(nMotor, StopDecel) == OK )
1190 m_bAreMotorsPowered =
true;
1191 RtDb.m_robotstatus.m_bAreMotorsPowered = m_bAreMotorsPowered;
1197 rc = -LAE_ECODE_BAD_OP;
1205 int LaeKinematics::stop(
const string &strName)
1207 LaeMapPowertrain::iterator pos;
1216 m_pAction->terminate();
1218 if( (pos = m_kinPowertrains.find(strName)) != m_kinPowertrains.end() )
1220 nCtlr = pos->second.getMotorCtlrId();
1221 nMotor = pos->second.getMotorIndex();
1224 rc = m_pMotorCtlr[nCtlr]->cmdStopWithDecel(nMotor, StopDecel);
1228 m_bAreMotorsPowered =
true;
1229 RtDb.m_robotstatus.m_bAreMotorsPowered = m_bAreMotorsPowered;
1234 rc = -LAE_ECODE_MOT_CTLR;
1239 LOGWARN(
"Powertrain %s: Not found.", strName.c_str());
1240 rc = -LAE_ECODE_BAD_VAL;
1245 rc = -LAE_ECODE_BAD_OP;
1253 int LaeKinematics::waitForAllStop(
double fSeconds)
1255 static const useconds_t WaitDt = 100;
1257 int nMaxTries = (int)ceil(fSeconds * MILLION / (
double)WaitDt);
1259 for(
int i = 0; i < nMaxTries; ++i)
1268 LOGERROR(
"Timed out waiting for %.2lf seconds for all joints to stop.",
1271 return -LAE_ECODE_TIMEDOUT;
1274 int LaeKinematics::setGoalVelocities(
const LaeMapVelocity &velocity)
1287 if( m_pAction->getActionType() != LaeKinAction::ActionTypeVelocity )
1289 m_pAction = LaeKinAction::replaceAction(*
this, m_pAction,
1290 LaeKinAction::ActionTypeVelocity);
1296 rc = pAction->
update(velocity);
1300 rc = pAction->
plan();
1305 if( (rc = pAction->
execute()) == LAE_OK )
1307 m_bAreMotorsPowered =
true;
1308 RtDb.m_robotstatus.m_bAreMotorsPowered = m_bAreMotorsPowered;
1314 rc = -LAE_ECODE_BAD_OP;
1322 int LaeKinematics::setGoalDutyCycles(
const LaeMapDutyCycle &duty)
1335 if( m_pAction->getActionType() != LaeKinAction::ActionTypeDutyCycle )
1337 m_pAction = LaeKinAction::replaceAction(*
this, m_pAction,
1338 LaeKinAction::ActionTypeDutyCycle);
1344 rc = pAction->
update(duty);
1348 rc = pAction->
plan();
1353 if( (rc = pAction->
execute()) == LAE_OK )
1355 m_bAreMotorsPowered =
true;
1356 RtDb.m_robotstatus.m_bAreMotorsPowered = m_bAreMotorsPowered;
1362 rc = -LAE_ECODE_BAD_OP;
1370 int LaeKinematics::setGoalTwist(
double fVelLinear,
double fVelAngular)
1383 if( m_pAction->getActionType() != LaeKinAction::ActionTypeTwist )
1385 m_pAction = LaeKinAction::replaceAction(*
this, m_pAction,
1386 LaeKinAction::ActionTypeTwist);
1392 rc = pAction->
update(fVelLinear, fVelAngular);
1396 rc = pAction->
plan();
1401 if( (rc = pAction->
execute()) == LAE_OK )
1403 m_bAreMotorsPowered =
true;
1404 RtDb.m_robotstatus.m_bAreMotorsPowered = m_bAreMotorsPowered;
1410 rc = -LAE_ECODE_BAD_OP;
1423 int LaeKinematics::sense()
1428 rc = senseDynamics();
1435 int LaeKinematics::senseDynamics()
1439 double amp[LaeNumMotorsPerCtlr];
1440 uint_t buflen[LaeNumMotorsPerCtlr];
1456 for(nCtlr = 0; nCtlr < LaeNumMotorCtlrs; ++nCtlr)
1461 m_pMotorCtlr[nCtlr]->cmdReadMotorCurrentDraw(amp[0], amp[1]);
1462 m_pMotorCtlr[nCtlr]->cmdReadCmdBufLengths(buflen[0], buflen[1]);
1467 for(nMotor = 0; nMotor < LaeNumMotorsPerCtlr; ++nMotor)
1469 m_pMotorCtlr[nCtlr]->cmdReadQEncoder(nMotor, encoder);
1470 m_pMotorCtlr[nCtlr]->cmdReadQSpeed(nMotor, speed);
1472 if( (pTrain = getPowertrain(nCtlr, nMotor)) == NULL )
1479 if(
iabs(speed) > SpeedReallyZero )
1484 RtDb.m_motorctlr[nCtlr].m_fMotorCurrent[nMotor] = amp[nMotor];
1488 m_kinPlatform.updateStateDynamics(m_kinPowertrains);
1490 m_bIsStopped = bIsStopped;
1491 RtDb.m_robotstatus.m_bInMotion = m_bIsStopped?
false:
true;
1496 int LaeKinematics::react()
1501 int LaeKinematics::plan()
1512 else if( m_pAction->isPlanningRequired() )
1514 rc = m_pAction->plan();
1526 int LaeKinematics::act()
1537 else if( m_pAction->isExecutionRequired() )
1539 rc = m_pAction->execute();
1551 int LaeKinematics::monitorHealth()
1570 for(nCtlr = 0; nCtlr < LaeNumMotorCtlrs; ++nCtlr)
1572 m_pMotorCtlr[nCtlr]->cmdReadMainBattVoltage(volts);
1573 m_pMotorCtlr[nCtlr]->cmdReadBoardTemperature(temp);
1574 m_pMotorCtlr[nCtlr]->cmdReadStatus(status);
1576 RtDb.m_motorctlr[nCtlr].m_uStatus = status;
1577 RtDb.m_motorctlr[nCtlr].m_fTemperature = temp;
1578 RtDb.m_motorctlr[nCtlr].m_fBatteryVoltage = volts;
1580 for(nMotor = 0; nMotor < LaeNumMotorsPerCtlr; ++nMotor)
1582 if( (pTrain = getPowertrain(nCtlr, nMotor)) != NULL )
1588 m_kinPlatform.updateCtlrHealth(nCtlr, volts, temp, status);
1591 m_kinPlatform.updateHealth(m_kinPowertrains);
1593 LOGDIAG4(
"Kinematics Thread: Monitored health of motor controllers.");
1600 void LaeKinematics::exec()
1610 if( m_bIsEnabled && !RtDb.m_enable.m_bMotorCtlr )
1612 LOGERROR(
"Motor controllers have been unexpectedly disaabled. Re-enable.");
1641 switch( eActionType )
1643 case ActionTypeVelocity:
1645 case ActionTypeDutyCycle:
1647 case ActionTypeTwist:
1649 case ActionTypeNavForDist:
1650 case ActionTypeNavToPos:
1652 case ActionTypeIdle:
1663 if( pAction != NULL )
1669 return newAction(kin, eNewActionType);
1685 LaeMapVelocity::const_iterator iter;
1686 LaeMapVelocity::iterator pos;
1694 for(iter = velocity.begin(); iter != velocity.end(); ++iter)
1706 else if( pos->second != iter->second )
1708 pos->second = iter->second;
1714 LOGDIAG3(
"Wheel %12s velocity = %lf rads/s.",
1715 iter->first.c_str(), iter->second);
1732 LaeMapVelocity::iterator goal;
1770 if(
m_speed[nCtlr][nMotor] != nSpeed )
1772 m_speed[nCtlr][nMotor] = nSpeed;
1825 LaeMapVelocity::iterator iter;
1879 LaeMapDutyCycle::const_iterator iter;
1880 LaeMapDutyCycle::iterator pos;
1888 for(iter = duty.begin(); iter != duty.end(); ++iter)
1900 else if( pos->second != iter->second )
1902 pos->second = iter->second;
1908 LOGDIAG3(
"Motor %12s duty = %5.3lf.", iter->first.c_str(), iter->second);
1925 LaeMapDutyCycle::iterator goal;
1957 fDuty[nMotor] = goal->second;
1962 fDuty[nMotor] = 0.0;
1987 LaeMapDutyCycle::iterator iter;
2040 LOGDIAG3(
"Robot linear velocity = %lf m/s, angular velocity = %lf deg/s.",
2072 double ppsAbsMax = 0.0;
2073 double ppsRatedMinMax = 10e10;
2091 ppsAng = velAngLin * ppm;
2095 pps[nCtlr][nMotor] = ppsLin - ppsAng;
2099 pps[nCtlr][nMotor] = ppsLin + ppsAng;
2103 if( fabs(pps[nCtlr][nMotor]) > ppsAbsMax )
2105 ppsAbsMax = fabs(pps[nCtlr][nMotor]);
2119 if( ppsAbsMax > ppsRatedMinMax )
2121 double derate = ppsRatedMinMax / ppsAbsMax;
2127 pps[nCtlr][nMotor] *= derate;
2139 nSpeed = (int)pps[nCtlr][nMotor];
2144 if(
m_speed[nCtlr][nMotor] != nSpeed )
2146 m_speed[nCtlr][nMotor] = nSpeed;
2199 LaeMapVelocity::iterator iter;
Laelaps kinematics base action class.
std::map< std::string, double > LaeMapDutyCycle
Duty cycle trajectory type.
LaeKinActionTwist(LaeKinematics &kin)
Default initialization constructor.
RoboClaw 2 motor controller class.
int m_nMotorCtlrId
motor controller id
Laelaps tuning data class.
Trajectory classes interfaces.
LaeDescBase * m_pDescBase
base description
Laelaps robotic mobile platform full description class.
int update(const LaeMapDutyCycle &dutycycle)
Update with new velocities.
LaePowertrain * getPowertrain(const std::string &strName)
Get pointer to powertrain by name (key).
virtual int terminate()
Terminate action.
virtual int updateStateDynamics(s64_t nEncoder, s32_t nSpeed, double fAmps, uint_t uBufLen)
Update state dynamics.
ActionType
Supported kinematic extended actions.
virtual int execute()
Execution new velocities.
void getVelPidKParams(const std::string &strName, double &fKp, double &fKi, double &fKd) const
Get motor velocity PID K tune parameters.
Laelaps kinematics class.
std::string m_strName
powertrain unique name (key)
LaeKinematics & m_kin
bound kinematics driver
s32_t m_speed[LaeNumMotorCtlrs][LaeNumMotorsPerCtlr]
target motor speeds (qpps)
int m_nMotorIndex
motor controller unique motor index
move robot by twist values
RoboClaw motor controller class interface.
virtual bool hasTerminated() const
Test if action has been terminated.
virtual int updateHealth(double fVolts, double fTemp, uint_t uCtlrStatus)
Update motor health state.
virtual bool isExecutionRequired() const
Test if more action requires (more) execution.
virtual int configure(const LaeDescPowertrain &desc)
Configure powertrain from product description.
double m_fGoalVelLinear
goal platform linear velocity
Laelaps kinematics duty cycle action class.
virtual bool isPlanningRequired()
Test if action requires (re)planning.
virtual int cmdDutyDrive2(double duty1, double duty2)
Drive both motors at the given duty cycle.
motor::roboclaw::RoboClaw * getMotorCtlr(const int nMotorCtlrId)
Get pointer to motor controller by name (key).
static const int LaeMotorLeft
left motors
double radToDeg(double r)
Convert radians to degrees.
ActionState m_eActionState
action state.
virtual int cmdQDriveWithAccel(int motor, s32_t speed, u32_t accel)
Drive a motor at the given speed and with the given acceleration.
static const int LAE_ECODE_MOT_CTLR
motor controller error
LaePowertrainAttr m_attr
semi-fixed attribute data
MapDescPowertrain m_mapDescPowertrain
powertrain descriptions
int update(const LaeMapVelocity &velocity)
Update with new velocities.
The <b><i>Laelaps</i></b> namespace encapsulates all <b><i>Laelaps</i></b> related constructs...
s64_t iabs(s64_t a)
Integer absolute value.
uint_t m_uMaxQpps
maximum quadrature pulses/second rps
std::string getName() const
Get this powertrain unique name (key).
Laelaps common utilities.
Laelaps kinematics velocity action class.
The Laelaps kinematics and dynamics class interface.
Laelaps powertrain class interfaces.
virtual int execute()
Execution [sub]action.
virtual int resetOdometer()
Reset odometry to zero.
virtual int execute()
Execution new velocities.
int update(double fVelLinear, double fVelAngular)
Update with new velocities.
move by motor duty cycles
double m_fMetersPerPulse
tire meters per encoder pulse
double m_fGoalVelAngular
goal platform angular velocity
LaePlatform & getPlatform()
Get robot platform kinodynamics.
Laelaps motors, encoder, and controllers hardware abstraction interfaces.
virtual int terminate()
Terminate action.
virtual int cmdStopWithDecel(int motor, u32_t decel)
Stop a motor with the given maximum decelerations.
static const int LaeNumMotorCtlrs
number of motor controllers
double m_fWheelRadsPerPulse
output shaft radians per encoder pulse
virtual int terminate()
Terminate action.
virtual int execute()
Execution new velocities.
#define LAE_VERSION(major, minor, revision)
Convert version triplet to integer equivalent.
LaeMapVelocity m_mapGoalVel
map of goal velocities
LaeKinActionDutyCycle(LaeKinematics &kin)
Default initialization constructor.
LaeMapDutyCycle m_mapGoalDutyCycle
map of goal duty cycles
Powertrain state data class.
LaePowertrainState m_state
dynamic state data
static const int LaeMotorRight
right motors
virtual int plan()
Plan next execution.
std::map< std::string, double > LaeMapVelocity
Velocity trajectory type.
Laelaps real-time "database".
Laelaps kinematics velocity action class.
virtual int terminate()
Terminate action.
s32_t m_speed[LaeNumMotorCtlrs][LaeNumMotorsPerCtlr]
target motor speeds (qpps)
virtual int plan()
Plan next execution.
update action specific data
static const int LaeNumMotorsPerCtlr
number of motors/controller
virtual int plan()
Plan next execution.
int m_nSpeed
raw speed (qpps)
std::string getRealDeviceName(const std::string &strDevName)
Get real device name.
Top-level package include file.
static const int LAE_OK
not an error, success