49 #include <sys/types.h> 55 #include "rnr/rnrconfig.h" 57 #include "rnr/serdev.h" 78 #define ROBOCLAW_TRY_MOTOR(motor) \ 81 if( !isValidMotor(motor) ) \ 83 LOGERROR("Motor controller 0x%02x: Motor index %d invalid.", \ 89 #undef ROBOCLAW_DBG_ENABLE 90 #ifdef ROBOCLAW_DBG_ENABLE
100 #define ROBOCLAW_DBG(addr, cmdNum, fmt, ...) \ 101 fprintf(stderr, "DBG: %s[%d]: Motor controller=0x%02x: Cmd=%d: " fmt, \ 102 __FILE__, __LINE__, addr, cmdNum, ##__VA_ARGS__) 114 #define ROBOCLAW_DBG_MSG(addr, cmdNum, buf, len, fmt, ...) \ 117 fprintf(stderr, "DBG: %s[%d]: Motor controller=0x%02x: Cmd=%d " fmt, \ 118 __FILE__, __LINE__, addr, cmdNum, ##__VA_ARGS__); \ 119 for(int i=0;i<len; ++i) { fprintf(stderr, "0x%02x ", buf[i]); } \ 120 fprintf(stderr, "\n"); \ 131 #define ROBOCLAW_DBG_BUF(buf, len, fmt, ...) \ 134 fprintf(stderr, "DBG: %s[%d]: " fmt, __FILE__, __LINE__, ##__VA_ARGS__); \ 135 for(int i=0;i<len; ++i) { fprintf(stderr, "0x%02x ", buf[i]); } \ 136 fprintf(stderr, "\n"); \ 144 #define ROBOCLAW_DBG(addr, cmdNum, fmt, ...) 149 #define ROBOCLAW_DBG_MSG(addr, cmdNum, buf, len, fmt, ...) 154 #define ROBOCLAW_DBG_BUF(buf, len, fmt, ...) \ 156 #endif // ROBOCLAW_DBG_ENABLE 175 RoboClawChipSelect::RoboClawChipSelect()
180 RoboClawChipSelect::~RoboClawChipSelect()
185 void RoboClawChipSelect::select(
int fd, byte_t addrSel)
187 m_addrLast = addrSel;
198 RoboClawComm::RoboClawComm()
203 m_bDbgEnable =
false;
206 RoboClawComm::RoboClawComm(std::string &strDevName,
213 m_bDbgEnable =
false;
215 open(strDevName, nBaudRate, pChipSelect);
218 RoboClawComm::~RoboClawComm()
223 int RoboClawComm::open(std::string &strDevName,
227 m_fd = SerDevOpen(strDevName.c_str(), nBaudRate, 8,
'N', 1,
false,
false);
231 LOGERROR(
"Failed to open %s@%d.", strDevName.c_str(), nBaudRate);
237 m_strDevName = strDevName;
238 m_nBaudRate = nBaudRate;
239 m_pChipSelect = pChipSelect == NULL? &csNoOp: pChipSelect;
241 LOGDIAG3(
"Opened interface to RoboClaw motor controller %s@%d.",
242 strDevName.c_str(), nBaudRate);
247 int RoboClawComm::close()
252 LOGDIAG3(
"Closed %s interface to RoboClaw motor controller.",
253 m_strDevName.c_str());
256 m_strDevName.clear();
260 m_bDbgEnable =
false;
265 int RoboClawComm::flushInput()
267 SerDevFIFOInputFlush(m_fd);
270 int RoboClawComm::execCmd(byte_t cmd[],
size_t lenCmd)
274 LOGWARN(
"Motor controller 0x%02x: execCmd() function is deprecated.");
276 if( (rc = sendCmd(cmd, lenCmd)) != OK )
278 LOGERROR(
"Motor controller 0x%02x: Failed to send command %u.",
279 cmd[FieldPosAddr], cmd[FieldPosCmd]);
286 int RoboClawComm::execCmdWithAckRsp(byte_t cmd[],
size_t lenCmd,
MsgFmt fmtCmd)
290 if( (rc = sendCmd(cmd, lenCmd, fmtCmd)) == OK )
292 if( (rc = recvAck()) != OK )
294 LOGERROR(
"Motor controller 0x%02x: Failed to receive ack for command %u.",
295 cmd[FieldPosAddr], cmd[FieldPosCmd]);
301 LOGERROR(
"Motor controller 0x%02x: Failed to send command %u.",
302 cmd[FieldPosAddr], cmd[FieldPosCmd]);
314 int RoboClawComm::execCmdWithDataRsp(byte_t cmd[],
size_t lenCmd,
315 byte_t rsp[],
size_t lenRsp,
322 if( (rc = sendCmd(cmd, lenCmd, fmtCmd)) == OK )
324 if( (n = recvDataRsp(rsp, lenRsp)) == (
int)lenRsp )
328 uCrcCalc = crc16(m_uCrcCmd, rsp, lenRsp-2);
329 if( m_uCrcRsp != uCrcCalc )
331 LOGERROR(
"Motor controller 0x%02x: " 332 "Command %u response CRC-16 mismatch: " 333 "Expected 0x%04x, received 0x%04x.",
334 cmd[FieldPosAddr], cmd[FieldPosCmd],
335 uCrcCalc, m_uCrcRsp);
342 LOGWARN(
"Motor controller 0x%02x: " 343 "Command %u received partial response of %d/%zu bytes - ignoring.",
344 cmd[FieldPosAddr], cmd[FieldPosCmd], n, lenRsp);
349 LOGERROR(
"Motor controller 0x%02x: Command %u received no response.",
350 cmd[FieldPosAddr], cmd[FieldPosCmd]);
356 LOGERROR(
"Motor controller 0x%02x: Failed to send command %u.",
357 cmd[FieldPosAddr], cmd[FieldPosCmd]);
369 int RoboClawComm::sendCmd(byte_t cmd[],
size_t lenCmd,
MsgFmt fmtCmd)
371 m_pChipSelect->select(m_fd, cmd[FieldPosAddr]);
374 m_uCrcCmd = crc16(0, cmd, lenCmd);
379 pack16(m_uCrcCmd, &cmd[lenCmd]);
386 "Motor controller=0x%02x: Cmd=%d: CRC=0x%04x: sendCmd(): ",
387 cmd[FieldPosAddr], cmd[FieldPosCmd], m_uCrcCmd);
390 if( SerDevWrite(m_fd, cmd, lenCmd, CmdTimeout) == lenCmd )
400 int RoboClawComm::recvDataRsp(byte_t rsp[],
size_t lenRsp)
404 if( (n = SerDevRead(m_fd, rsp, lenRsp, RspTimeout)) >= 0 )
409 unpack16(&rsp[n-2], m_uCrcRsp);
425 int RoboClawComm::recvAck()
430 n = SerDevRead(m_fd, &ack, 1, RspTimeout);
452 int RoboClawComm::pack16(uint_t val, byte_t buf[])
454 buf[0] = (byte_t)((val >> 8) & 0xff);
455 buf[1] = (byte_t)(val & 0xff);
459 int RoboClawComm::unpack16(byte_t buf[], uint_t &val)
461 val = ((uint_t)(buf[0]) << 8) | (uint_t)buf[1];
465 int RoboClawComm::unpack16(byte_t buf[],
int &val)
469 v = ((s16_t)(buf[0]) << 8) | (s16_t)buf[1];
475 int RoboClawComm::pack32(uint_t val, byte_t buf[])
477 buf[0] = (byte_t)((val >> 24) & 0xff);
478 buf[1] = (byte_t)((val >> 16) & 0xff);
479 buf[2] = (byte_t)((val >> 8) & 0xff);
480 buf[3] = (byte_t)(val & 0xff);
484 int RoboClawComm::unpack32(byte_t buf[], uint_t &val)
486 val = ((uint_t)(buf[0]) << 24) |
487 ((uint_t)(buf[1]) << 16) |
488 ((uint_t)(buf[2]) << 8) |
493 int RoboClawComm::unpack32(byte_t buf[],
int &val)
497 v = ((s32_t)(buf[0]) << 24) |
498 ((s32_t)(buf[1]) << 16) |
499 ((s32_t)(buf[2]) << 8) |
506 byte_t RoboClawComm::checksum(byte_t buf[],
size_t lenBuf,
bool bAck)
512 for(i=0, sum=0; i<lenBuf; ++i)
514 sum += (uint_t)buf[i];
517 chksum = (byte_t)(sum) & CheckSumMask;
527 uint_t RoboClawComm::crc16(uint_t crc, byte_t buf[],
size_t lenBuf)
532 for(i = 0; i < lenBuf; ++i)
534 crc = crc ^ ((uint_t)buf[i] << 8);
536 for(bit = 0; bit < 8; ++bit)
540 crc = (crc << 1) ^ 0x1021;
557 const byte_t address,
558 const string &strNameId) :
559 m_comm(comm), m_address(address), m_strNameId(strNameId)
561 for(
int i=0; i<NumMotors; ++i)
563 m_nMotorDir[i] = MotorDirNormal;
569 RoboClaw::~RoboClaw()
571 if( m_comm.isOpen() )
577 bool RoboClaw::probe(byte_t address)
579 byte_t cmd[CmdMaxBufLen];
580 byte_t rsp[RspMaxBufLen];
587 rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 4);
597 int RoboClaw::cmdReadFwVersion(
string &strFwVer)
599 byte_t cmd[CmdMaxBufLen];
600 byte_t rsp[RspMaxBufLen];
606 cmd[n++] = m_address;
609 if( m_comm.sendCmd(cmd, n) != OK )
614 n = m_comm.recvDataRsp(rsp, ParamVerLen);
616 if( n > ParamVerLenMin )
621 uCrcCmd = m_comm.getLastCmdCrc();
622 uCrcRsp = m_comm.getLastRspCrc();
623 uCrcCalc = m_comm.crc16(uCrcCmd, rsp, n-2);
625 if( uCrcRsp != uCrcCalc )
627 LOGERROR(
"Motor controller 0x%02x: " 628 "Command %u response CRC-16 mismatch: " 629 "Expected 0x%04x, received 0x%04x.",
630 cmd[FieldPosAddr], cmd[FieldPosCmd],
635 rsp[n-ParamVerLenMin] = 0;
636 strFwVer = (
char *)rsp;
638 LOGDIAG3(
"%s.", strFwVer.c_str());
644 LOGERROR(
"Motor controller 0x%02x: " 645 "Failed to receive firmware version.",
656 int RoboClaw::cmdReadMainBattVoltage(
double &volts)
658 byte_t cmd[CmdMaxBufLen];
659 byte_t rsp[RspMaxBufLen];
664 cmd[n++] = m_address;
667 if( (rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 4)) == OK )
669 m_comm.unpack16(rsp, val);
670 volts = (double)val * ParamVoltScale;
676 void RoboClaw::getMainBattCutoffRange(
double &minmin,
double &maxmax)
const 678 minmin = ParamVoltMainMin;
679 maxmax = ParamVoltMax;
683 int RoboClaw::cmdReadMainBattCutoffs(
double &min,
double &max)
685 byte_t cmd[CmdMaxBufLen];
686 byte_t rsp[RspMaxBufLen];
688 uint_t valMin, valMax;
691 cmd[n++] = m_address;
694 if( (rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 6)) == OK )
696 n = m_comm.unpack16(rsp, valMin);
697 n += m_comm.unpack16(rsp+n, valMax);
700 "MainBatt Cutoffs [%u, %u]\n", valMin, valMax);
702 min = (double)valMin * ParamVoltScale;
703 max = (double)valMax * ParamVoltScale;
710 int RoboClaw::cmdSetMainBattCutoffs(
const double min,
const double max)
712 byte_t cmd[CmdMaxBufLen];
715 uint_t valMin, valMax;
718 fMin = min / ParamVoltScale;
719 valMin = (uint_t)
fcap(fMin, ParamVoltMainMin, ParamVoltMax);
721 fMax = max / ParamVoltScale;
722 valMax = (uint_t)
fcap(fMax, fMin, ParamVoltMax);
727 cmd[n++] = m_address;
733 k = m_comm.pack16(valMin, cmd+n);
736 k = m_comm.pack16(valMax, cmd+n);
739 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
750 int RoboClaw::cmdReadMotorCurrentDraw(
double &s1,
double &s2)
752 byte_t cmd[CmdMaxBufLen];
753 byte_t rsp[RspMaxBufLen];
758 cmd[n++] = m_address;
761 if( (rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 6)) == OK )
765 k = m_comm.unpack16(rsp, val1);
768 k = m_comm.unpack16(rsp+n, val2);
771 amps1 = (double)val1 * ParamAmpScale;
772 amps2 = (double)val2 * ParamAmpScale;
782 int RoboClaw::cmdReadMotorMaxCurrentLimit(
int motor,
double &maxAmps)
784 byte_t cmd[CmdMaxBufLen];
785 byte_t rsp[RspMaxBufLen];
791 cmd[n++] = m_address;
794 m_comm.enableDbg(
true);
796 rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 10);
802 k = m_comm.unpack32(rsp, val1);
805 k = m_comm.unpack32(rsp+n, val2);
808 maxAmps = (double)val1 * ParamAmpScale;
809 minAmps = (double)val2 * ParamAmpScale;
812 m_comm.enableDbg(
false);
821 int RoboClaw::cmdSetMotorMaxCurrentLimit(
int motor,
const double maxAmps)
823 byte_t cmd[CmdMaxBufLen];
824 byte_t rsp[RspMaxBufLen];
833 fMax =
fcap(maxAmps, ParamAmpMinSane, 100.0);
834 valMax = (uint_t)(fMax / ParamAmpScale);
841 cmd[n++] = m_address;
847 k = m_comm.pack32(valMax, cmd+n);
850 k = m_comm.pack32(valMin, cmd+n);
854 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
862 int RoboClaw::cmdReadLogicVoltage(
double &volts)
864 byte_t cmd[CmdMaxBufLen];
865 byte_t rsp[RspMaxBufLen];
870 cmd[n++] = m_address;
873 if( (rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 4)) == OK )
875 m_comm.unpack16(rsp, val);
876 volts = (double)val * ParamVoltScale;
882 void RoboClaw::getLogicCutoffRange(
double &minmin,
double &maxmax)
const 884 minmin = ParamVoltLogicMin;
885 maxmax = ParamVoltMax;
889 int RoboClaw::cmdReadLogicCutoffs(
double &min,
double &max)
891 byte_t cmd[CmdMaxBufLen];
892 byte_t rsp[RspMaxBufLen];
894 uint_t valMin, valMax;
897 cmd[n++] = m_address;
900 if( (rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 6)) == OK )
902 n = m_comm.unpack16(rsp, valMin);
903 n += m_comm.unpack16(rsp+n, valMax);
906 "Logic Cutoffs [%u, %u]\n", valMin, valMax);
908 min = (double)valMin * ParamVoltScale;
909 max = (double)valMax * ParamVoltScale;
916 int RoboClaw::cmdSetLogicCutoffs(
const double min,
const double max)
918 byte_t cmd[CmdMaxBufLen];
921 uint_t valMin, valMax;
924 fMin = min / ParamVoltScale;
925 valMin = (uint_t)
fcap(fMin, ParamVoltLogicMin, ParamVoltMax);
927 fMax = max / ParamVoltScale;
928 valMax = (uint_t)
fcap(fMax, fMin, ParamVoltMax);
930 cmd[n++] = m_address;
933 k = m_comm.pack16(valMin, cmd+n);
936 k = m_comm.pack16(valMax, cmd+n);
939 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
947 int RoboClaw::cmdReadVelocityPidConst(
int motor,
953 byte_t cmd[CmdMaxBufLen];
954 byte_t rsp[RspMaxBufLen];
958 cmd[n++] = m_address;
961 if( (rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 18)) == OK )
965 k = m_comm.unpack32(rsp, Kp);
968 k = m_comm.unpack32(rsp+n, Ki);
971 k = m_comm.unpack32(rsp+n, Kd);
974 k = m_comm.unpack32(rsp+n, qpps);
978 "VelPid: motor=%d, P=0x%08x, I=0x%08x, D=0x%08x, Q=%u\n",
979 motor, Kp, Ki, Kd, qpps);
986 int RoboClaw::cmdSetVelocityPidConst(
int motor,
992 byte_t cmd[CmdMaxBufLen];
993 byte_t rsp[RspMaxBufLen];
999 cmd[n++] = m_address;
1003 k = m_comm.pack32(Kd, cmd+n);
1006 k = m_comm.pack32(Kp, cmd+n);
1009 k = m_comm.pack32(Ki, cmd+n);
1012 k = m_comm.pack32(qpps, cmd+n);
1015 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1023 int RoboClaw::cmdReadBoardTemperature(
double &temp)
1025 byte_t cmd[CmdMaxBufLen];
1026 byte_t rsp[RspMaxBufLen];
1031 cmd[n++] = m_address;
1034 if( (rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 4)) == OK )
1036 m_comm.unpack16(rsp, val);
1037 temp = (double)val * ParamTempScale;
1044 int RoboClaw::cmdReadStatus(uint_t &status)
1046 byte_t cmd[CmdMaxBufLen];
1047 byte_t rsp[RspMaxBufLen];
1052 cmd[n++] = m_address;
1055 if( (rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 4)) == OK )
1057 m_comm.unpack16(rsp, status);
1064 int RoboClaw::cmdReadCmdBufLengths(uint_t &len1, uint_t &len2)
1066 byte_t cmd[CmdMaxBufLen];
1067 byte_t rsp[RspMaxBufLen];
1072 cmd[n++] = m_address;
1075 if( (rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 4)) == OK )
1077 len1 = (uint_t)rsp[0];
1078 len2 = (uint_t)rsp[1];
1089 int RoboClaw::cmdReadEncoderMode(byte_t &mode1, byte_t &mode2)
1091 byte_t cmd[CmdMaxBufLen];
1092 byte_t rsp[RspMaxBufLen];
1097 cmd[n++] = m_address;
1100 if( (rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 4)) == OK )
1112 int RoboClaw::cmdSetEncoderMode(
int motor, byte_t mode)
1114 byte_t cmd[CmdMaxBufLen];
1115 byte_t mask = ParamEncModeRCAnalogBit | ParamEncModeQuadAbsBit;
1120 cmd[n++] = m_address;
1122 cmd[n++] = (byte_t)(mask & mode);
1124 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1128 int RoboClaw::cmdSetEncoderMode2(byte_t mode1, byte_t mode2)
1132 if( (rc = cmdSetEncoderMode(Motor1, mode1)) == OK )
1134 rc = cmdSetEncoderMode(Motor2, mode2);
1141 int RoboClaw::cmdResetQEncoders()
1143 byte_t cmd[CmdMaxBufLen];
1147 cmd[n++] = m_address;
1150 if( (rc = m_comm.execCmdWithAckRsp(cmd, n,
MsgWithCrc)) == OK )
1152 for(
int i=0; i<NumMotors; ++i)
1163 int RoboClaw::cmdReadQEncoder(
int motor, s64_t &encoder)
1165 static s64_t MaxEncDelta = 2048;
1167 byte_t cmd[CmdMaxBufLen];
1168 byte_t rsp[RspMaxBufLen];
1179 cmd[n++] = m_address;
1182 if( (rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 7)) == OK )
1185 "cmdReadQEncoder(motor=%d): rsp = ", motor);
1196 n = m_comm.unpack32(rsp, enc32);
1199 enc64 = (s64_t)enc32;
1215 if( status & ParamEncStatusUnderFlow )
1217 LOGDIAG2(
"Motor controller 0x%02x: Motor %d: Encoder underflow: " 1219 m_address, motor, enc32);
1221 if( status & ParamEncStatusOverFlow )
1223 LOGDIAG2(
"Motor controller 0x%02x: Motor %d: Encoder overflow: " 1225 m_address, motor, enc32);
1233 if( status & ParamEncStatusDirBackward )
1235 if( enc64 <= m_nEncPrev[motor] )
1237 delta = enc64 - m_nEncPrev[motor];
1241 delta = enc64 - ParamEncQuadMax - m_nEncPrev[motor];
1242 if(
iabs(delta) > MaxEncDelta )
1244 delta = enc64 - m_nEncPrev[motor];
1256 if( enc64 >= m_nEncPrev[motor] )
1258 delta = enc64 - m_nEncPrev[motor];
1262 delta = enc64 + ParamEncQuadMax - m_nEncPrev[motor];
1263 if(
iabs(delta) > MaxEncDelta )
1265 delta = enc64 - m_nEncPrev[motor];
1273 m_nEncoder[motor] += (m_nMotorDir[motor] * delta);
1274 m_nEncPrev[motor] = enc64;
1275 encoder = m_nEncoder[motor];
1286 int RoboClaw::cmdDutyDrive2(
double duty1,
double duty2)
1288 byte_t cmd[CmdMaxBufLen];
1292 speed1 = (int)((
double)duty1 * ParamDutyCycleMax);
1293 speed2 = (int)((
double)duty2 * ParamDutyCycleMax);
1295 cmd[n++] = m_address;
1298 k = m_comm.pack16((
int)speed1, cmd+n);
1301 k = m_comm.pack16((
int)speed2, cmd+n);
1304 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1312 int RoboClaw::cmdReadQSpeed(
int motor, s32_t &speed)
1314 byte_t cmd[CmdMaxBufLen];
1315 byte_t rsp[RspMaxBufLen];
1323 cmd[n++] = m_address;
1326 if( (rc = m_comm.execCmdWithDataRsp(cmd, n, rsp, 7)) == OK )
1329 "cmdReadQSpeed(motor=%d): rsp = ", motor);
1331 n = m_comm.unpack32(rsp, val);
1335 if( status & ParamEncStatusDirBackward )
1345 int RoboClaw::cmdQDrive(
int motor, s32_t speed)
1347 byte_t cmd[CmdMaxBufLen];
1352 speed *= m_nMotorDir[motor];
1354 cmd[n++] = m_address;
1357 k = m_comm.pack32((
int)speed, cmd+n);
1361 "cmdQDrive(motor=%d, speed=%d): cmd = ", motor, speed);
1363 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1367 int RoboClaw::cmdQDrive2(s32_t speed1, s32_t speed2)
1369 byte_t cmd[CmdMaxBufLen];
1372 speed1 *= m_nMotorDir[Motor1];
1373 speed2 *= m_nMotorDir[Motor2];
1375 cmd[n++] = m_address;
1378 k = m_comm.pack32((
int)speed1, cmd+n);
1381 k = m_comm.pack32((
int)speed2, cmd+n);
1384 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1388 int RoboClaw::cmdQDriveWithAccel(
int motor, s32_t speed, u32_t accel)
1390 byte_t cmd[CmdMaxBufLen];
1395 speed *= m_nMotorDir[motor];
1397 cmd[n++] = m_address;
1400 k = m_comm.pack32((uint_t)accel, cmd+n);
1403 k = m_comm.pack32((
int)speed, cmd+n);
1406 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1410 int RoboClaw::cmdQDriveWithAccel(s32_t speed1, u32_t accel1,
1411 s32_t speed2, u32_t accel2)
1413 byte_t cmd[CmdMaxBufLen];
1416 speed1 *= m_nMotorDir[Motor1];
1417 speed2 *= m_nMotorDir[Motor2];
1419 cmd[n++] = m_address;
1422 k = m_comm.pack32((uint_t)accel1, cmd+n);
1425 k = m_comm.pack32((
int)speed1, cmd+n);
1428 k = m_comm.pack32((uint_t)accel2, cmd+n);
1431 k = m_comm.pack32((
int)speed2, cmd+n);
1434 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1438 int RoboClaw::cmdQDriveForDist(
int motor, s32_t speed, u32_t dist,
bool bQueue)
1440 byte_t cmd[CmdMaxBufLen];
1445 speed *= m_nMotorDir[motor];
1447 cmd[n++] = m_address;
1450 k = m_comm.pack32((
int)speed, cmd+n);
1453 k = m_comm.pack32((uint_t)dist, cmd+n);
1456 cmd[n++] = bQueue? ParamCmdBufQueue: ParamCmdBufPreempt;
1458 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1462 int RoboClaw::cmdQDriveForDist(s32_t speed1, u32_t dist1,
1463 s32_t speed2, u32_t dist2,
1466 byte_t cmd[CmdMaxBufLen];
1469 speed1 *= m_nMotorDir[Motor1];
1470 speed2 *= m_nMotorDir[Motor2];
1472 cmd[n++] = m_address;
1475 k = m_comm.pack32((
int)speed1, cmd+n);
1478 k = m_comm.pack32((uint_t)dist1, cmd+n);
1481 k = m_comm.pack32((
int)speed2, cmd+n);
1484 k = m_comm.pack32((uint_t)dist2, cmd+n);
1487 cmd[n++] = bQueue? ParamCmdBufQueue: ParamCmdBufPreempt;
1489 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1493 int RoboClaw::cmdQDriveWithAccelForDist(
int motor,
1499 byte_t cmd[CmdMaxBufLen];
1504 speed *= m_nMotorDir[motor];
1506 cmd[n++] = m_address;
1510 k = m_comm.pack32((uint_t)accel, cmd+n);
1513 k = m_comm.pack32((
int)speed, cmd+n);
1516 k = m_comm.pack32((uint_t)dist, cmd+n);
1519 cmd[n++] = bQueue? ParamCmdBufQueue: ParamCmdBufPreempt;
1521 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1525 int RoboClaw::cmdQDriveWithAccelForDist(s32_t speed1,
1533 byte_t cmd[CmdMaxBufLen];
1536 speed1 *= m_nMotorDir[Motor1];
1537 speed2 *= m_nMotorDir[Motor2];
1539 cmd[n++] = m_address;
1540 cmd[n++] = CmdBufDriveQAccel2Dist;
1542 k = m_comm.pack32((uint_t)accel1, cmd+n);
1545 k = m_comm.pack32((
int)speed1, cmd+n);
1548 k = m_comm.pack32((uint_t)dist1, cmd+n);
1551 k = m_comm.pack32((uint_t)accel2, cmd+n);
1554 k = m_comm.pack32((
int)speed2, cmd+n);
1557 k = m_comm.pack32((uint_t)dist2, cmd+n);
1560 cmd[n++] = bQueue? ParamCmdBufQueue: ParamCmdBufPreempt;
1562 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1566 int RoboClaw::cmdQDriveWithProfileToPos(
int motor,
1573 byte_t cmd[CmdMaxBufLen];
1578 speed *= m_nMotorDir[motor];
1580 cmd[n++] = m_address;
1584 k = m_comm.pack32((uint_t)accel, cmd+n);
1587 k = m_comm.pack32((
int)speed, cmd+n);
1590 k = m_comm.pack32((uint_t)deccel, cmd+n);
1593 k = m_comm.pack32((
int)pos, cmd+n);
1596 cmd[n++] = bQueue? ParamCmdBufQueue: ParamCmdBufPreempt;
1598 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1602 int RoboClaw::cmdQDriveWithProfileToPos(s32_t speed1,
1612 byte_t cmd[CmdMaxBufLen];
1615 speed1 *= m_nMotorDir[Motor1];
1616 speed2 *= m_nMotorDir[Motor2];
1618 cmd[n++] = m_address;
1621 k = m_comm.pack32((uint_t)accel1, cmd+n);
1624 k = m_comm.pack32((
int)speed1, cmd+n);
1627 k = m_comm.pack32((uint_t)deccel1, cmd+n);
1630 k = m_comm.pack32((
int)pos1, cmd+n);
1633 k = m_comm.pack32((uint_t)accel2, cmd+n);
1636 k = m_comm.pack32((
int)speed2, cmd+n);
1639 k = m_comm.pack32((uint_t)deccel2, cmd+n);
1642 k = m_comm.pack32((
int)pos2, cmd+n);
1645 cmd[n++] = bQueue? ParamCmdBufQueue: ParamCmdBufPreempt;
1647 return m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
1651 int RoboClaw::cmdSDrive(
int motor,
int speed)
1653 byte_t cmd[CmdMaxBufLen];
1658 speed =
RoboClaw::cap(speed, MotorSpeedMaxBackward, MotorSpeedMaxForward);
1659 speed *= m_nMotorDir[motor];
1663 cmd[n++] = m_address;
1665 cmd[n++] = (byte_t)speed;
1669 cmd[n++] = m_address;
1671 cmd[n++] = (byte_t)(-speed);
1674 return m_comm.execCmdWithAckRsp(cmd, n,
MsgWithCrc);
1678 int RoboClaw::cmdSDrive2(
int speed1,
int speed2)
1682 if( (rc = cmdSDrive(Motor1, speed1)) == OK )
1684 rc = cmdSDrive(Motor2, speed2);
1694 int RoboClaw::cmdStop(
int motor)
1696 return cmdQDrive(motor, 0);
1700 int RoboClaw::cmdStopWithDecel(
int motor, u32_t decel)
1702 return cmdQDriveWithAccel(motor, 0, decel);
1706 int RoboClaw::cmdStop()
1708 return cmdQDrive2(0, 0);
1712 int RoboClaw::cmdStopWithDecel(u32_t decel)
1714 return cmdQDriveWithAccel(0, decel, 0, decel);
1718 int RoboClaw::cmdEStop()
1734 int RoboClaw::cmdWriteSettingsToEEPROM()
1736 byte_t cmd[CmdMaxBufLen];
1740 cmd[n++] = m_address;
1749 rc = m_comm.execCmdWithAckRsp(cmd, n, MsgWithCrc);
drive motros at qpps with 2 accel vals
#define ROBOCLAW_DBG_MSG(addr, cmdNum, buf, len, fmt,...)
Debug print message disabled.
buffered drive motor 1 to dist at qpps
message includes a 16-bit CRC
read motor 2 velocity PID constants
buffered drive motor 2 to dist at qpps with accel.
static RoboClawChipSelect csNoOp
read current board status
read motor 1 speed (qpps)
drive motor 1 at quad. pulses/second
reset encoder (quadrature )counters
double fcap(double a, double min, double max)
Cap value within limits [min, max].
drive motor 1 at quad. pps with accel.
drive motors with signed qpps, accel, deccel and position
RoboClaw motor controller class interface.
set main battery voltage cutoffs
buffered drive motor 2 to dist at qpps
buffered drive motors to dist at qpps w/ 2 accel
drive motor 2 with signed qpps, accel, deccel and position
set motor 2 velocity PID constants
read motor 1 maximum current limit
set motor 1 maximum current limit
RoboClaw motor controller chip select class.
s64_t iabs(s64_t a)
Integer absolute value.
set motor 1 velocity PID constants
int cap(int a, int min, int max)
Cap value within limits [min, max].
read encoder mode for both motors
#define ROBOCLAW_TRY_MOTOR(motor)
Test for valid motor index.
drive motors at quad. pulses/second
read motor 2 speed (qpps)
read motors bufferd command length
read main battery voltage
drive motor 1 with signed qpps, accel, deccel and position
read main battery cutoff settings
#define ROBOCLAW_DBG(addr, cmdNum, fmt,...)
Debug print disabled.
read logic voltage cutoff settings
#define ROBOCLAW_DBG_BUF(buf, len, fmt,...)
Debug print buffer disabled.
buffered drive motor 1 to dist at qpps with accel.
buffered drive motors to dist at qpps
drive motor 2 at quad. pps with accel.
RoboClaw communication class.
set logic voltage cutoffs
drive motor 2 at quad. pulses/second
MsgFmt
Command and response message formats.
drive motors at duty cycle (no quad.)
read motor 2 maximum current limit
read logic battery voltage
set motor 2 maximum current limit