32 #include <boost/assign.hpp>
33 #include <boost/math/special_functions/round.hpp>
36 #include <linux/i2c-dev.h>
37 #include <linux/i2c.h>
39 #include <sys/ioctl.h>
40 #define I2C_DEVICE "/dev/i2c-1" // This is specific to default Magni I2C port on host
52 #define TICKS_PER_RAD_FROM_GEAR_RATIO ((double)(4.774556)*(double)(2.0)) // Used to generate ticks per radian
53 #define TICKS_PER_RADIAN_DEFAULT 41.004 // For runtime use getWheelGearRatio() * TICKS_PER_RAD_FROM_GEAR_RATIO
54 #define WHEEL_GEAR_RATIO_DEFAULT WHEEL_GEAR_RATIO_1
57 #define HIGH_SPEED_RADIANS (1.8) // threshold to consider wheel turning 'very fast'
58 #define WHEEL_VELOCITY_NEAR_ZERO ((double)(0.08))
59 #define ODOM_4WD_ROTATION_SCALE ((double)(1.65)) // Used to correct for 4WD skid rotation error
61 #define MOTOR_AMPS_PER_ADC_COUNT ((double)(0.0238)) // 0.1V/Amp 2.44V=1024 count so 41.97 cnt/amp
63 #define VELOCITY_READ_PER_SECOND ((double)(10.0)) // read = ticks / (100 ms), so we scale of 10 for ticks/second
64 #define LOWEST_FIRMWARE_VERSION 28
113 static int i2c_BufferRead(
const char *i2cDevFile, uint8_t i2c8bitAddr,
114 uint8_t *pBuffer, int16_t chipRegAddr, uint16_t NumBytesToRead);
119 boost::assign::list_of(
"left_wheel_joint")(
"right_wheel_joint");
121 for (
size_t i = 0; i < joint_names.size(); i++) {
128 joint_state_handle, &
joints_[i].velocity_command);
136 ROS_INFO(
"Delay before MCB serial port initialization");
138 ROS_INFO(
"Initialize MCB serial port '%s' for %d baud",
144 ROS_INFO(
"MCB serial port initialized");
224 for (
size_t i = 0; i <
sizeof(
joints_) /
sizeof(
joints_[0]); i++) {
246 ubiquity_motor::MotorState mstateMsg;
248 mstateMsg.header.frame_id =
"";
254 mstateMsg.rightRotateRate =
joints_[WheelJointLocation::Right].
velocity;
277 ROS_WARN(
"Firmware System Event for PowerOn transition");
283 ROS_FATAL(
"Firmware version %d, expect %d or above",
285 throw std::runtime_error(
"Firmware version too low");
313 int16_t odomLeft = (odom >> 16) & 0xffff;
314 int16_t odomRight = odom & 0xffff;
325 double odom4wdRotationScale = 1.0;
332 int leftDir = (leftWheelVel >= (double)(0.0)) ? 1 : -1;
333 int rightDir = (rightWheelVel >= (double)(0.0)) ? 1 : -1;
340 && ((leftDir + rightDir) == 0)
343 && ((fabs(leftWheelVel) > near0WheelVel) && (fabs(rightWheelVel) > near0WheelVel))
346 && ((fabs(leftWheelVel) - fabs(rightWheelVel)) < near0WheelVel) ) {
349 if ((index % 16) == 1) {
350 ROS_INFO(
"ROTATIONAL_SCALING_ACTIVE: odom4wdRotationScale = %4.2f [%4.2f, %4.2f] [%d,%d] opt 0x%x 4wd=%d",
351 odom4wdRotationScale, leftWheelVel, rightWheelVel, leftDir, rightDir,
fw_params.
hw_options, is4wdMode);
354 if (fabs(leftWheelVel) > near0WheelVel) {
355 ROS_DEBUG(
"odom4wdRotationScale = %4.2f [%4.2f, %4.2f] [%d,%d] opt 0x%x 4wd=%d",
356 odom4wdRotationScale, leftWheelVel, rightWheelVel, leftDir, rightDir,
fw_params.
hw_options, is4wdMode);
371 std_msgs::Int32 left;
372 std_msgs::Int32 right;
374 int16_t leftSpeed = (speed >> 16) & 0xffff;
375 int16_t rightSpeed = speed & 0xffff;
377 left.data = leftSpeed;
378 right.data = rightSpeed;
385 int32_t bothPwm = mm.
getData();
459 ROS_WARN(
"right PWM limit reached");
463 ROS_DEBUG(
"left Integral limit reached");
467 ROS_DEBUG(
"right Integral limit reached");
471 ROS_WARN(
"left Maximum speed reached");
475 ROS_WARN(
"right Maximum speed reached");
486 sensor_msgs::BatteryState bstate;
489 bstate.current = std::numeric_limits<float>::quiet_NaN();
490 bstate.charge = std::numeric_limits<float>::quiet_NaN();
491 bstate.capacity = std::numeric_limits<float>::quiet_NaN();
492 bstate.design_capacity = std::numeric_limits<float>::quiet_NaN();
496 bstate.power_supply_status = sensor_msgs::BatteryState::POWER_SUPPLY_STATUS_UNKNOWN;
497 bstate.power_supply_health = sensor_msgs::BatteryState::POWER_SUPPLY_HEALTH_UNKNOWN;
498 bstate.power_supply_technology = sensor_msgs::BatteryState::POWER_SUPPLY_TECHNOLOGY_UNKNOWN;
511 ROS_WARN(
"Motor power has gone from inactive to active. Most likely from ESTOP switch");
516 ROS_WARN(
"Motor power has gone inactive. Most likely from ESTOP switch active");
522 std_msgs::Bool estop_message;
529 uint16_t leftTickSpacing = (
data >> 16) & 0xffff;
530 uint16_t rightTickSpacing =
data & 0xffff;
531 uint16_t tickCap = 0;
533 if ((tickCap > 0) && (leftTickSpacing > tickCap)) { leftTickSpacing = tickCap; }
534 if ((tickCap > 0) && (rightTickSpacing > tickCap)) { rightTickSpacing = tickCap; }
537 std_msgs::Int32 leftInterval;
538 std_msgs::Int32 rightInterval;
540 leftInterval.data = leftTickSpacing;
541 rightInterval.data = rightTickSpacing;
548 ROS_DEBUG(
"Tic Ints M1 %d [0x%x] M2 %d [0x%x]",
549 leftTickSpacing, leftTickSpacing, rightTickSpacing, rightTickSpacing);
564 std_msgs::String fstate;
568 std::stringstream stream;
570 std::string daycode(stream.str());
572 fstate.data +=
" "+daycode;
585 float onecell = voltage / (float)cells;
587 if(onecell >= type[10])
589 else if(onecell <= type[0])
595 for(
int i = 0; i < 11; i++){
596 if(onecell > type[i]){
604 float deltavoltage = type[
upper] - type[
lower];
605 float between_percent = (onecell - type[
lower]) / deltavoltage;
607 return (
float)
lower * 0.1 + between_percent * 0.1;
627 ROS_WARN(
"Wheel rotation at high radians per sec. Left %f rad/s Right %f rad/s",
628 left_radians, right_radians);
635 int32_t
data = (left_speed << 16) | (right_speed & 0x0000ffff);
638 std_msgs::Int32 smsg;
639 smsg.data = left_speed;
672 if ((std::abs(left_radians) < wheelSpeedRadPerSec) &&
673 (std::abs(right_radians) < wheelSpeedRadPerSec)) {
739 ROS_INFO(
"setting estop button detection to %x", (
int)estop_detection);
767 switch(new_wheel_type) {
770 ROS_INFO_ONCE(
"setting MCB wheel type %d", (
int)new_wheel_type);
778 ROS_ERROR(
"Illegal MCB wheel type 0x%x will not be set!", (
int)new_wheel_type);
803 ROS_INFO(
"Setting Wheel gear ratio to %6.4f and tics_per_radian to %6.4f",
822 ROS_INFO_ONCE(
"setting MCB pid control word to 0x%x", (
int)pid_control_word);
833 ROS_DEBUG(
"Nulling MCB wheel errors using current wheel positions");
837 mm.
setData(MotorOrWheelNumber::Motor_M1|MotorOrWheelNumber::Motor_M2);
844 ROS_INFO(
"setting MCB wheel direction to %d", (
int)wheel_direction);
856 return pidControlWord;
865 ROS_INFO(
"reading MCB option switch on the I2C bus");
868 ROS_ERROR(
"Error %d in reading MCB option switch at 8bit Addr 0x%x",
871 }
else if (retCount != 1) {
875 retBits = (0xff) & ~buf[0];
883 ROS_INFO(
"setting MCB option switch register to 0x%x", (
int)option_switch_bits);
887 os.
setData(option_switch_bits);
931 ROS_ERROR(
"setting deadzone enable to %d", (
int)deadzone_enable);
968 std::vector<MotorMessage> commands;
987 commands.push_back(p);
998 commands.push_back(i);
1010 commands.push_back(
d);
1022 commands.push_back(v);
1034 commands.push_back(denominator);
1048 commands.push_back(winsize);
1060 commands.push_back(maxpwm);
1072 commands.push_back(mmsg);
1077 if (commands.size() != 0) {
1088 std::vector<MotorMessage> commands;
1098 commands.push_back(led1);
1108 commands.push_back(led2);
1118 double encoderFactor = 1.0;
1124 encoderFactor = (double)(0.5);
1128 speed = boost::math::iround(speedFloat);
1142 using diagnostic_msgs::DiagnosticStatus;
1147 stat.
summary(DiagnosticStatus::ERROR,
"No firmware version reported. Power may be off.");
1150 stat.
summary(DiagnosticStatus::WARN,
"Firmware is older than recommended! You must update firmware!");
1153 stat.
summary(DiagnosticStatus::OK,
"Firmware version is OK");
1161 std::stringstream stream;
1163 std::string daycode(stream.str());
1165 stat.
add(
"Firmware Date", daycode);
1166 stat.
summary(DiagnosticStatus::OK,
"Firmware daycode format is YYYYMMDD");
1173 stat.
summary(DiagnosticStatus::OK,
"Limits reached:");
1175 stat.
mergeSummary(DiagnosticStatusWrapper::ERROR,
" left pwm,");
1179 stat.
mergeSummary(DiagnosticStatusWrapper::ERROR,
" right pwm,");
1183 stat.
mergeSummary(DiagnosticStatusWrapper::WARN,
" left integral,");
1187 stat.
mergeSummary(DiagnosticStatusWrapper::WARN,
" right integral,");
1191 stat.
mergeSummary(DiagnosticStatusWrapper::WARN,
" left speed,");
1195 stat.
mergeSummary(DiagnosticStatusWrapper::WARN,
" right speed,");
1200 stat.
mergeSummary(DiagnosticStatusWrapper::WARN,
" firmware limit,");
1208 stat.
summary(DiagnosticStatusWrapper::WARN,
"Battery low");
1211 stat.
summary(DiagnosticStatusWrapper::ERROR,
"Battery critical");
1214 stat.
summary(DiagnosticStatusWrapper::OK,
"Battery OK");
1221 stat.
summary(DiagnosticStatus::OK,
"PID Parameter P");
1225 stat.
summary(DiagnosticStatus::OK,
"PID Parameter I");
1229 stat.
summary(DiagnosticStatus::OK,
"PID Parameter D");
1233 stat.
summary(DiagnosticStatus::OK,
"PID Parameter V");
1237 stat.
summary(DiagnosticStatus::OK,
"PID Max PWM");
1244 stat.
summary(DiagnosticStatusWrapper::OK,
"Motor power on");
1247 stat.
summary(DiagnosticStatusWrapper::WARN,
"Motor power off");
1255 std::string option_descriptions(
"");
1257 option_descriptions +=
"High resolution encoders";
1259 option_descriptions +=
"Standard resolution encoders";
1262 option_descriptions +=
", Thin gearless wheels";
1264 option_descriptions +=
", Standard wheels";
1267 option_descriptions +=
", 4 wheel drive";
1269 option_descriptions +=
", 2 wheel drive";
1273 option_descriptions +=
", Reverse polarity wheels";
1275 stat.
summary(DiagnosticStatusWrapper::OK, option_descriptions);
1288 uint8_t *pBuffer, int16_t chipRegAddr, uint16_t NumBytesToRead)
1294 int address = i2c8bitAddr >> 1;
1297 if ((fd = open(i2cDevFile, O_RDWR)) < 0) {
1299 ROS_ERROR(
"Cannot open I2C def of %s with error %s", i2cDevFile, strerror(errno));
1300 goto exitWithNoClose;
1304 if (ioctl(fd, I2C_SLAVE, address) != 0) {
1306 ROS_ERROR(
"Failed to get bus access to I2C device %s! ERROR: %s", i2cDevFile, strerror(errno));
1307 goto exitWithFileClose;
1310 if (chipRegAddr < 0) {
1311 buf[0] = (uint8_t)(chipRegAddr);
1312 if ((write(fd, buf, 1)) != 1) {
1314 goto exitWithFileClose;
1318 bytesRead = read(fd, pBuffer, NumBytesToRead);
1319 if (bytesRead != NumBytesToRead) {
1321 goto exitWithFileClose;
1323 retCode = bytesRead;