00001 #include <algorithm>
00002 #include <iostream>
00003
00004 #include <segwayrmp/segwayrmp.h>
00005 #include <segwayrmp/impl/rmp_io.h>
00006 #include <segwayrmp/impl/rmp_ftd2xx.h>
00007 #if defined(SEGWAYRMP_USE_SERIAL)
00008 # include <segwayrmp/impl/rmp_serial.h>
00009 #endif
00010
00011 #if !HAS_CLOCK_GETTIME
00012 # include <sys/time.h>
00013 #endif
00014
00015 inline void
00016 defaultSegwayStatusCallback(segwayrmp::SegwayStatus::Ptr &segway_status)
00017 {
00018 std::cout << "Segway Status:" << std::endl << std::endl
00019 << segway_status->str() << std::endl << std::endl;
00020 }
00021
00022 inline void defaultDebugMsgCallback(const std::string &msg)
00023 {
00024 std::cerr << "SegwayRMP Debug: " << msg << std::endl;
00025 }
00026
00027 inline void defaultInfoMsgCallback(const std::string &msg)
00028 {
00029 std::cerr << "SegwayRMP Info: " << msg << std::endl;
00030 }
00031
00032 inline void defaultErrorMsgCallback(const std::string &msg)
00033 {
00034 std::cerr << "SegwayRMP Error: " << msg << std::endl;
00035 }
00036
00037
00038
00039 inline segwayrmp::SegwayTime defaultTimestampCallback()
00040 #ifndef WIN32
00041 throw(segwayrmp::NoHighPerformanceTimersException)
00042 #endif
00043 {
00044 segwayrmp::SegwayTime st;
00045 #ifndef WIN32
00046 # if HAS_CLOCK_GETTIME
00047 timespec start;
00048 clock_gettime(CLOCK_REALTIME, &start);
00049 st.sec = start.tv_sec;
00050 st.nsec = start.tv_nsec;
00051 # else
00052 struct timeval timeofday;
00053 gettimeofday(&timeofday, NULL);
00054 st.sec = timeofday.tv_sec;
00055 st.nsec = timeofday.tv_usec * 1000;
00056 # endif
00057 #else
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069 static LARGE_INTEGER cpu_freq, init_cpu_time;
00070 uint32_t start_sec = 0;
00071 uint32_t start_nsec = 0;
00072 if ( ( start_sec == 0 ) && ( start_nsec == 0 ) ) {
00073 QueryPerformanceFrequency(&cpu_freq);
00074 if (cpu_freq.QuadPart == 0) {
00075 throw segwayrmp::NoHighPerformanceTimersException();
00076 }
00077 QueryPerformanceCounter(&init_cpu_time);
00078
00079
00080 FILETIME ft;
00081 GetSystemTimeAsFileTime(&ft);
00082 LARGE_INTEGER start_li;
00083 start_li.LowPart = ft.dwLowDateTime;
00084 start_li.HighPart = ft.dwHighDateTime;
00085
00086
00087 # ifdef _MSC_VER
00088 start_li.QuadPart -= 116444736000000000Ui64;
00089 # else
00090 start_li.QuadPart -= 116444736000000000ULL;
00091 # endif
00092
00093 start_sec = (uint32_t)(start_li.QuadPart / 10000000);
00094 start_nsec = (start_li.LowPart % 10000000) * 100;
00095 }
00096 LARGE_INTEGER cur_time;
00097 QueryPerformanceCounter(&cur_time);
00098 LARGE_INTEGER delta_cpu_time;
00099 delta_cpu_time.QuadPart = cur_time.QuadPart - init_cpu_time.QuadPart;
00100
00101
00102
00103 double d_delta_cpu_time =
00104 delta_cpu_time.QuadPart / (double) cpu_freq.QuadPart;
00105 uint32_t delta_sec = (uint32_t) floor(d_delta_cpu_time);
00106 uint32_t delta_nsec =
00107 (uint32_t) boost::math::round((d_delta_cpu_time - delta_sec) * 1e9);
00108
00109 int64_t sec_sum = (int64_t)start_sec + (int64_t)delta_sec;
00110 int64_t nsec_sum = (int64_t)start_nsec + (int64_t)delta_nsec;
00111
00112
00113 normalizeSecNSecUnsigned(sec_sum, nsec_sum);
00114
00115 st.sec = sec_sum;
00116 st.nsec = nsec_sum;
00117 #endif
00118 return st;
00119 }
00120
00121 inline void defaultExceptionCallback(const std::exception &error)
00122 {
00123 std::cerr << "SegwayRMP Unhandled Exception: " << error.what()
00124 << std::endl;
00125 }
00126
00127 inline void printHex(char *data, int length)
00128 {
00129 for (int i = 0; i < length; ++i) {
00130 printf("0x%.2X ", (unsigned)(unsigned char)data[i]);
00131 }
00132 printf("\n");
00133 }
00134
00135 inline void printHexFromString(std::string str)
00136 {
00137 printHex(const_cast<char *>(str.c_str()), str.length());
00138 }
00139
00140 using namespace segwayrmp;
00141
00142 SegwayStatus::SegwayStatus()
00143 : timestamp(SegwayTime(0, 0)), pitch(0.0f), pitch_rate(0.0f), roll(0.0f),
00144 roll_rate(0.0f), left_wheel_speed(0.0f), right_wheel_speed(0.0f),
00145 yaw_rate(0.0f), servo_frames(0.0f), integrated_left_wheel_position(0.0f),
00146 integrated_right_wheel_position(0.0f), integrated_forward_position(0.0f),
00147 integrated_turn_position(0.0f), left_motor_torque(0.0f),
00148 right_motor_torque(0.0f), ui_battery_voltage(0.0f),
00149 powerbase_battery_voltage(0.0f), commanded_velocity(0.0f),
00150 commanded_yaw_rate(0.0f), operational_mode(disabled),
00151 controller_gain_schedule(light), motor_status(0), touched(false)
00152 {}
00153
00154 std::string SegwayStatus::str()
00155 {
00156 std::stringstream ss;
00157 ss << "Time Stamp: "
00158 << "\n Seconds: " << timestamp.sec
00159 << "\n Nanoseconds: " << timestamp.nsec
00160 << "\nPitch: " << pitch << "\nPitch Rate: " << pitch_rate
00161 << "\nRoll: " << roll << "\nRoll Rate: " << roll_rate
00162 << "\nLeft Wheel Speed: " << left_wheel_speed
00163 << "\nRight Wheel Speed: " << right_wheel_speed
00164 << "\nYaw Rate: " << yaw_rate
00165 << "\nServo Frames: " << servo_frames
00166 << "\nIntegrated Left Wheel Position: " << integrated_left_wheel_position
00167 << "\nIntegrated Right Wheel Position: "
00168 << integrated_right_wheel_position
00169 << "\nIntegrated Forward Displacement: " << integrated_forward_position
00170 << "\nIntegrated Turn Position: " << integrated_turn_position
00171 << "\nLeft Motor Torque: " << left_motor_torque
00172 << "\nRight Motor Torque: " << right_motor_torque
00173 << "\nUI Battery Voltage: " << ui_battery_voltage
00174 << "\nPowerbase Battery Voltage: " << powerbase_battery_voltage
00175 << "\nOperational Mode: ";
00176 switch (operational_mode) {
00177 case disabled:
00178 ss << "disabled";
00179 break;
00180 case tractor:
00181 ss << "tractor";
00182 break;
00183 case balanced:
00184 ss << "balanced";
00185 break;
00186 case power_down:
00187 ss << "power down";
00188 break;
00189 default:
00190 ss << "unknown";
00191 break;
00192 }
00193 ss << "\nController Gain Schedule: ";
00194 switch (controller_gain_schedule) {
00195 case light:
00196 ss << "light";
00197 break;
00198 case tall:
00199 ss << "tall";
00200 break;
00201 case heavy:
00202 ss << "heavy";
00203 break;
00204 default:
00205 ss << "unknown";
00206 break;
00207 }
00208 ss << "\nCommanded Velocity: " << commanded_velocity
00209 << "\nCommanded Yaw Rate: " << commanded_yaw_rate
00210 << "\nMotor Status: ";
00211 if (motor_status) {
00212 ss << "Motors Enabled";
00213 } else {
00214 ss << "E-Stopped";
00215 }
00216 return ss.str();
00217 }
00218
00219 SegwayRMP::SegwayRMP(InterfaceType interface_type,
00220 SegwayRMPType segway_rmp_type)
00221 : interface_type_(no_interface), segway_rmp_type_(segway_rmp_type),
00222 connected_(false),
00223 continuously_reading_(false),
00224 status_callback_(defaultSegwayStatusCallback),
00225 get_time_(defaultTimestampCallback),
00226 debug_(defaultDebugMsgCallback),
00227 info_(defaultInfoMsgCallback),
00228 error_(defaultErrorMsgCallback),
00229 handle_exception_(defaultExceptionCallback)
00230 {
00231 this->segway_status_ = SegwayStatus::Ptr(new SegwayStatus());
00232 this->interface_type_ = interface_type;
00233 switch (interface_type) {
00234 case can:
00235 RMP_THROW_MSG(ConfigurationException, "CAN is not supported currently");
00236 break;
00237 case usb:
00238 this->rmp_io_ = new FTD2XXRMPIO();
00239 break;
00240 case serial:
00241 #if defined(SEGWAYRMP_USE_SERIAL)
00242 this->rmp_io_ = new SerialRMPIO();
00243 #else
00244 RMP_THROW_MSG(ConfigurationException, "Library is not built with Serial "
00245 "support");
00246 #endif
00247 break;
00248 case ethernet:
00249 RMP_THROW_MSG(ConfigurationException, "Ethernet is not currently "
00250 "supported");
00251 break;
00252 case no_interface:
00253
00254 break;
00255 default:
00256 RMP_THROW_MSG(ConfigurationException, "Invalid InterfaceType specified");
00257 break;
00258 }
00259
00260
00261 this->SetConstantsBySegwayType_(this->segway_rmp_type_);
00262 }
00263
00264 SegwayRMP::~SegwayRMP()
00265 {
00266 if (this->continuously_reading_) {
00267 this->StopReadingContinuously_();
00268 }
00269 if (this->interface_type_ == serial) {
00270 #if defined(SEGWAYRMP_USE_SERIAL)
00271 SerialRMPIO * ptr = (SerialRMPIO *)(this->rmp_io_);
00272 delete ptr;
00273 #endif
00274 }
00275 if (this->interface_type_ == usb) {
00276 FTD2XXRMPIO * ptr = (FTD2XXRMPIO *)(this->rmp_io_);
00277 delete ptr;
00278 }
00279 }
00280
00281 void SegwayRMP::configureSerial(std::string port, int baudrate)
00282 {
00283 #if SEGWAYRMP_USE_SERIAL
00284 if (this->interface_type_ == serial) {
00285 SerialRMPIO *serial_rmp = (SerialRMPIO *)(this->rmp_io_);
00286 serial_rmp->configure(port, baudrate);
00287 } else {
00288 RMP_THROW_MSG(ConfigurationException, "configureSerial: Cannot configure "
00289 "serial when the InterfaceType is not serial.");
00290 }
00291 #else
00292 RMP_THROW_MSG(ConfigurationException, "configureSerial: The segwayrmp "
00293 "library is not build with serial support, not implemented.");
00294 #endif
00295 }
00296
00297 void SegwayRMP::configureUSBBySerial(std::string serial_number, int baudrate)
00298 {
00299 if (this->interface_type_ == usb) {
00300 FTD2XXRMPIO *ftd2xx_rmp = (FTD2XXRMPIO *)(this->rmp_io_);
00301 ftd2xx_rmp->configureUSBBySerial(serial_number, baudrate);
00302 } else {
00303 RMP_THROW_MSG(ConfigurationException, "configureUSBBySerial: Cannot "
00304 "configure ftd2xx usb when the InterfaceType is not usb.");
00305 }
00306 }
00307
00308 void SegwayRMP::configureUSBByDescription(std::string description,
00309 int baudrate)
00310 {
00311 if (this->interface_type_ == usb) {
00312 FTD2XXRMPIO *ftd2xx_rmp = (FTD2XXRMPIO *)(this->rmp_io_);
00313 ftd2xx_rmp->configureUSBByDescription(description, baudrate);
00314 } else {
00315 RMP_THROW_MSG(ConfigurationException, "configureUSBByDescription: "
00316 "Cannot configure ftd2xx usb when the InterfaceType is not usb.");
00317 }
00318 }
00319
00320 void SegwayRMP::configureUSBByIndex(int device_index, int baudrate)
00321 {
00322 if (this->interface_type_ == usb) {
00323 FTD2XXRMPIO *ftd2xx_rmp = (FTD2XXRMPIO *)(this->rmp_io_);
00324 ftd2xx_rmp->configureUSBByIndex(device_index, baudrate);
00325 } else {
00326 RMP_THROW_MSG(ConfigurationException, "configureUSBByIndex: "
00327 "Cannot configure ftd2xx usb when the InterfaceType is not usb.");
00328 }
00329 }
00330
00331 void SegwayRMP::connect(bool reset_integrators)
00332 {
00333
00334 this->rmp_io_->connect();
00335
00336 this->connected_ = true;
00337
00338 if (reset_integrators) {
00339
00340 this->resetAllIntegrators();
00341 }
00342
00343
00344 this->StartReadingContinuously_();
00345
00346 }
00347
00348 void SegwayRMP::shutdown()
00349 {
00350
00351 if (!this->connected_)
00352 RMP_THROW_MSG(ConfigurationException, "Cannot send shutdown: "
00353 "Not Connected.");
00354 try {
00355 Packet packet;
00356
00357 packet.id = 0x0412;
00358
00359 this->rmp_io_->sendPacket(packet);
00360 } catch (std::exception &e) {
00361 std::stringstream ss;
00362 ss << "Cannot send shutdown: " << e.what();
00363 RMP_THROW_MSG(ConfigurationException, ss.str().c_str());
00364 }
00365 }
00366
00367 void SegwayRMP::moveCounts(short int linear_counts, short int angular_counts)
00368 {
00369
00370 if (!this->connected_)
00371 RMP_THROW_MSG(MoveFailedException, "Not Connected.");
00372 try {
00373 short int lc = linear_counts;
00374 short int ac = angular_counts;
00375 Packet packet;
00376
00377 packet.id = 0x0413;
00378
00379 packet.data[0] = (unsigned char)((lc & 0xFF00) >> 8);
00380 packet.data[1] = (unsigned char)(lc & 0x00FF);
00381 packet.data[2] = (unsigned char)((ac & 0xFF00) >> 8);
00382 packet.data[3] = (unsigned char)(ac & 0x00FF);
00383 packet.data[4] = 0x00;
00384 packet.data[5] = 0x00;
00385 packet.data[6] = 0x00;
00386 packet.data[7] = 0x00;
00387
00388 this->rmp_io_->sendPacket(packet);
00389 } catch (std::exception &e) {
00390 RMP_THROW_MSG(MoveFailedException, e.what());
00391 }
00392 }
00393
00394 void SegwayRMP::move(float linear_velocity, float angular_velocity)
00395 {
00396
00397 if (!this->connected_)
00398 RMP_THROW_MSG(MoveFailedException, "Not Connected.");
00399 try {
00400 short int lv = (short int)(linear_velocity * this->mps_to_counts_);
00401 short int av = (short int)(angular_velocity * this->dps_to_counts_);
00402
00403 Packet packet;
00404
00405 packet.id = 0x0413;
00406
00407 packet.data[0] = (unsigned char)((lv & 0xFF00) >> 8);
00408 packet.data[1] = (unsigned char)(lv & 0x00FF);
00409 packet.data[2] = (unsigned char)((av & 0xFF00) >> 8);
00410 packet.data[3] = (unsigned char)(av & 0x00FF);
00411 packet.data[4] = 0x00;
00412 packet.data[5] = 0x00;
00413 packet.data[6] = 0x00;
00414 packet.data[7] = 0x00;
00415
00416 this->rmp_io_->sendPacket(packet);
00417 } catch (std::exception &e) {
00418 RMP_THROW_MSG(MoveFailedException, e.what());
00419 }
00420 }
00421
00422 void SegwayRMP::setOperationalMode(OperationalMode operational_mode)
00423 {
00424
00425 if (!this->connected_)
00426 RMP_THROW_MSG(ConfigurationException, "Cannot set operational mode: "
00427 "Not Connected.");
00428 try {
00429 Packet packet;
00430
00431 packet.id = 0x0413;
00432
00433 packet.data[0] = 0x00;
00434 packet.data[1] = 0x00;
00435 packet.data[2] = 0x00;
00436 packet.data[3] = 0x00;
00437 packet.data[4] = 0x00;
00438 packet.data[5] = 0x10;
00439 packet.data[6] = 0x00;
00440 packet.data[7] = (unsigned char)operational_mode;
00441
00442 this->rmp_io_->sendPacket(packet);
00443
00444
00445
00446
00447
00448 } catch (std::exception &e) {
00449 std::stringstream ss;
00450 ss << "Cannot set operational mode: " << e.what();
00451 RMP_THROW_MSG(ConfigurationException, ss.str().c_str());
00452 }
00453 }
00454
00455 void SegwayRMP::setControllerGainSchedule(
00456 ControllerGainSchedule controller_gain_schedule)
00457 {
00458
00459 if (!this->connected_)
00460 RMP_THROW_MSG(ConfigurationException, "Cannot set controller gain "
00461 "schedule: Not Connected.");
00462 try {
00463 Packet packet;
00464
00465 packet.id = 0x0413;
00466
00467 packet.data[0] = 0x00;
00468 packet.data[1] = 0x00;
00469 packet.data[2] = 0x00;
00470 packet.data[3] = 0x00;
00471 packet.data[4] = 0x00;
00472 packet.data[5] = 0x0D;
00473 packet.data[6] = 0x00;
00474 packet.data[7] = (unsigned char)controller_gain_schedule;
00475
00476 this->rmp_io_->sendPacket(packet);
00477
00478
00479
00480
00481
00482
00483
00484 } catch (std::exception &e) {
00485 std::stringstream ss;
00486 ss << "Cannot set controller gain schedule: " << e.what();
00487 RMP_THROW_MSG(ConfigurationException, ss.str().c_str());
00488 }
00489 }
00490
00491 void SegwayRMP::setBalanceModeLocking(bool state)
00492 {
00493
00494 if (!this->connected_)
00495 RMP_THROW_MSG(ConfigurationException, "Cannot set balance mode lock: "
00496 "Not Connected.");
00497 try {
00498 Packet packet;
00499
00500 packet.id = 0x0413;
00501
00502 packet.data[0] = 0x00;
00503 packet.data[1] = 0x00;
00504 packet.data[2] = 0x00;
00505 packet.data[3] = 0x00;
00506 packet.data[4] = 0x00;
00507 packet.data[5] = 0x0F;
00508 packet.data[6] = 0x00;
00509 if (state)
00510 packet.data[7] = 0x01;
00511 else
00512 packet.data[7] = 0x00;
00513
00514 this->rmp_io_->sendPacket(packet);
00515 } catch (std::exception &e) {
00516 std::stringstream ss;
00517 ss << "Cannot set balance mode lock: " << e.what();
00518 RMP_THROW_MSG(ConfigurationException, ss.str().c_str());
00519 }
00520 }
00521
00522 void SegwayRMP::resetAllIntegrators()
00523 {
00524
00525 if (!this->connected_)
00526 RMP_THROW_MSG(ConfigurationException, "Cannot reset Integrators: Not "
00527 "Connected.");
00528 try {
00529 Packet packet;
00530
00531 packet.id = 0x0413;
00532
00533 packet.data[0] = 0x00;
00534 packet.data[1] = 0x00;
00535 packet.data[2] = 0x00;
00536 packet.data[3] = 0x00;
00537 packet.data[4] = 0x00;
00538 packet.data[5] = 0x32;
00539 packet.data[6] = 0x00;
00540 packet.data[7] = 0x01;
00541
00542 this->rmp_io_->sendPacket(packet);
00543
00544 packet.data[7] = 0x02;
00545
00546 this->rmp_io_->sendPacket(packet);
00547
00548 packet.data[7] = 0x04;
00549
00550 this->rmp_io_->sendPacket(packet);
00551
00552 packet.data[7] = 0x08;
00553
00554 this->rmp_io_->sendPacket(packet);
00555
00556 } catch (std::exception &e) {
00557 std::stringstream ss;
00558 ss << "Cannot reset Integrators: " << e.what();
00559 RMP_THROW_MSG(ConfigurationException, ss.str().c_str());
00560 }
00561 }
00562
00563 void SegwayRMP::setMaxVelocityScaleFactor(double scalar)
00564 {
00565
00566 if (!this->connected_)
00567 RMP_THROW_MSG(ConfigurationException, "Cannot set max velocity scale "
00568 "factor: Not Connected.");
00569 try {
00570 Packet packet;
00571
00572 packet.id = 0x0413;
00573
00574 packet.data[0] = 0x00;
00575 packet.data[1] = 0x00;
00576 packet.data[2] = 0x00;
00577 packet.data[3] = 0x00;
00578 packet.data[4] = 0x00;
00579 packet.data[5] = 0x0A;
00580 packet.data[6] = 0x00;
00581
00582 if (scalar < 0.0)
00583 scalar = 0.0;
00584 if (scalar > 1.0)
00585 scalar = 1.0;
00586 scalar *= 16.0;
00587 scalar = floor(scalar);
00588
00589 short int scalar_int = (short int)scalar;
00590
00591 packet.data[7] = (unsigned char)(scalar_int & 0x00FF);
00592
00593 this->rmp_io_->sendPacket(packet);
00594 } catch (std::exception &e) {
00595 std::stringstream ss;
00596 ss << "Cannot set max velocity scale factor: " << e.what();
00597 RMP_THROW_MSG(ConfigurationException, ss.str().c_str());
00598 }
00599 }
00600
00601 void SegwayRMP::setMaxAccelerationScaleFactor(double scalar)
00602 {
00603
00604 if (!this->connected_)
00605 RMP_THROW_MSG(ConfigurationException, "Cannot set max acceleration scale "
00606 "factor: Not Connected.");
00607 try {
00608 Packet packet;
00609
00610 packet.id = 0x0413;
00611
00612 packet.data[0] = 0x00;
00613 packet.data[1] = 0x00;
00614 packet.data[2] = 0x00;
00615 packet.data[3] = 0x00;
00616 packet.data[4] = 0x00;
00617 packet.data[5] = 0x0B;
00618 packet.data[6] = 0x00;
00619
00620 if (scalar < 0.0)
00621 scalar = 0.0;
00622 if (scalar > 1.0)
00623 scalar = 1.0;
00624 scalar *= 16.0;
00625 scalar = floor(scalar);
00626
00627 short int scalar_int = (short int)scalar;
00628
00629 packet.data[7] = (unsigned char)(scalar_int & 0x00FF);
00630
00631 this->rmp_io_->sendPacket(packet);
00632 } catch (std::exception &e) {
00633 std::stringstream ss;
00634 ss << "Cannot set max acceleration scale factor: " << e.what();
00635 RMP_THROW_MSG(ConfigurationException, ss.str().c_str());
00636 }
00637 }
00638
00639 void SegwayRMP::setMaxTurnScaleFactor(double scalar)
00640 {
00641
00642 if (!this->connected_)
00643 RMP_THROW_MSG(ConfigurationException, "Cannot set max turn scale factor: "
00644 "Not Connected.");
00645 try {
00646 Packet packet;
00647
00648 packet.id = 0x0413;
00649
00650 packet.data[0] = 0x00;
00651 packet.data[1] = 0x00;
00652 packet.data[2] = 0x00;
00653 packet.data[3] = 0x00;
00654 packet.data[4] = 0x00;
00655 packet.data[5] = 0x0C;
00656 packet.data[6] = 0x00;
00657
00658 if (scalar < 0.0)
00659 scalar = 0.0;
00660 if (scalar > 1.0)
00661 scalar = 1.0;
00662 scalar *= 16.0;
00663 scalar = floor(scalar);
00664
00665 short int scalar_int = (short int)scalar;
00666
00667 packet.data[7] = (unsigned char)(scalar_int & 0x00FF);
00668
00669 this->rmp_io_->sendPacket(packet);
00670 } catch (std::exception &e) {
00671 std::stringstream ss;
00672 ss << "Cannot set max turn scale factor: " << e.what();
00673 RMP_THROW_MSG(ConfigurationException, ss.str().c_str());
00674 }
00675 }
00676
00677 void SegwayRMP::setCurrentLimitScaleFactor(double scalar)
00678 {
00679
00680 if (!this->connected_)
00681 RMP_THROW_MSG(ConfigurationException, "Cannot set current limit scale "
00682 "factor: Not Connected.");
00683 try {
00684 Packet packet;
00685
00686 packet.id = 0x0413;
00687
00688 packet.data[0] = 0x00;
00689 packet.data[1] = 0x00;
00690 packet.data[2] = 0x00;
00691 packet.data[3] = 0x00;
00692 packet.data[4] = 0x00;
00693 packet.data[5] = 0x0E;
00694 packet.data[6] = 0x00;
00695
00696 if (scalar < 0.0)
00697 scalar = 0.0;
00698 if (scalar > 1.0)
00699 scalar = 1.0;
00700 scalar *= 256.0;
00701 scalar = floor(scalar);
00702
00703 short int scalar_int = (short int)scalar;
00704
00705 packet.data[7] = (unsigned char)(scalar_int & 0x00FF);
00706
00707 this->rmp_io_->sendPacket(packet);
00708 } catch (std::exception &e) {
00709 std::stringstream ss;
00710 ss << "Cannot set current limit scale factor: " << e.what();
00711 RMP_THROW_MSG(ConfigurationException, ss.str().c_str());
00712 }
00713 }
00714
00715 void SegwayRMP::setStatusCallback(SegwayStatusCallback callback) {
00716 this->status_callback_ = callback;
00717 }
00718
00719 void SegwayRMP::setLogMsgCallback(std::string log_level,
00720 LogMsgCallback callback)
00721 {
00722
00723 std::transform(log_level.begin(), log_level.end(),
00724 log_level.begin(), ::tolower);
00725 if (log_level == "debug") {
00726 this->debug_ = callback;
00727 }
00728 if (log_level == "info") {
00729 this->info_ = callback;
00730 }
00731 if (log_level == "error") {
00732 this->error_ = callback;
00733 }
00734 }
00735
00736 void SegwayRMP::setTimestampCallback(GetTimeCallback callback) {
00737 this->get_time_ = callback;
00738 }
00739
00740 void SegwayRMP::setExceptionCallback(ExceptionCallback exception_callback) {
00741 this->handle_exception_ = exception_callback;
00742 }
00743
00744 void SegwayRMP::ReadContinuously_() {
00745 Packet packet;
00746 while (this->continuously_reading_) {
00747 try {
00748 this->rmp_io_->getPacket(packet);
00749 this->ProcessPacket_(packet);
00750 } catch (PacketRetrievalException &e) {
00751 if (e.error_number() == 2)
00752 this->error_("Checksum mismatch...");
00753 else if (e.error_number() == 3)
00754 this->error_("No data from Segway...");
00755 else
00756 this->handle_exception_(e);
00757 }
00758 }
00759 }
00760
00761 void SegwayRMP::ExecuteCallbacks_() {
00762 while (this->continuously_reading_) {
00763 SegwayStatus::Ptr ss = this->ss_queue_.dequeue();
00764 if (this->continuously_reading_) {
00765 try {
00766 if (ss) {
00767 if (this->status_callback_) {
00768 this->status_callback_(ss);
00769 }
00770 }
00771 } catch (std::exception &e) {
00772 this->handle_exception_(e);
00773 }
00774 }
00775 }
00776 }
00777
00778 void SegwayRMP::StartReadingContinuously_() {
00779 this->continuously_reading_ = true;
00780 this->read_thread_ =
00781 boost::thread(&SegwayRMP::ReadContinuously_, this);
00782 this->callback_execution_thread_ =
00783 boost::thread(&SegwayRMP::ExecuteCallbacks_, this);
00784 }
00785
00786 void SegwayRMP::StopReadingContinuously_()
00787 {
00788 this->continuously_reading_ = false;
00789 this->rmp_io_->cancel();
00790 this->read_thread_.join();
00791 this->ss_queue_.cancel();
00792 this->callback_execution_thread_.join();
00793 }
00794
00795 void SegwayRMP::SetConstantsBySegwayType_(SegwayRMPType &rmp_type) {
00796 if (rmp_type == rmp200 || rmp_type == rmp400) {
00797 this->dps_to_counts_ = 7.8;
00798 this->mps_to_counts_ = 332.0;
00799 this->meters_to_counts_ = 33215.0;
00800 this->rev_to_counts_ = 112644.0;
00801 this->torque_to_counts_ = 1094.0;
00802 } else
00803 if (rmp_type == rmp50 || rmp_type == rmp100) {
00804 this->dps_to_counts_ = 7.8;
00805 this->mps_to_counts_ = 401.0;
00806 this->meters_to_counts_ = 40181.0;
00807 this->rev_to_counts_ = 117031.0;
00808 this->torque_to_counts_ = 1463.0;
00809 } else {
00810 RMP_THROW_MSG(ConfigurationException, "Invalid Segway RMP Type");
00811 }
00812 }
00813
00814 inline short int getShortInt(unsigned char high, unsigned char low)
00815 {
00816 return (short int)(((unsigned short int)high << 8)
00817 | (unsigned short int)low);
00818 }
00819
00820 inline int
00821 getInt(unsigned char lhigh, unsigned char llow,
00822 unsigned char hhigh, unsigned char hlow)
00823 {
00824 int result = 0;
00825 char data[4] = {llow, lhigh, hlow, hhigh};
00826 memcpy(&result, data, 4);
00827 return result;
00828 }
00829
00830 bool SegwayRMP::ParsePacket_(Packet &packet, SegwayStatus::Ptr &ss_ptr)
00831 {
00832 bool status_updated = false;
00833 if (packet.channel == 0xBB)
00834 return status_updated;
00835
00836
00837 switch (packet.id) {
00838 case 0x0400:
00839
00840 ss_ptr->timestamp = this->get_time_();
00841 break;
00842 case 0x0401:
00843 ss_ptr->pitch = getShortInt(packet.data[0], packet.data[1])
00844 / this->dps_to_counts_;
00845 ss_ptr->pitch_rate = getShortInt(packet.data[2], packet.data[3])
00846 / this->dps_to_counts_;
00847 ss_ptr->roll = getShortInt(packet.data[4], packet.data[5])
00848 / this->dps_to_counts_;
00849 ss_ptr->roll_rate = getShortInt(packet.data[6], packet.data[7])
00850 / this->dps_to_counts_;
00851 ss_ptr->touched = true;
00852 break;
00853 case 0x0402:
00854 ss_ptr->left_wheel_speed = getShortInt(packet.data[0], packet.data[1])
00855 / this->mps_to_counts_;
00856 ss_ptr->right_wheel_speed = getShortInt(packet.data[2], packet.data[3])
00857 / this->mps_to_counts_;
00858 ss_ptr->yaw_rate = getShortInt(packet.data[4], packet.data[5])
00859 / this->dps_to_counts_;
00860 ss_ptr->servo_frames = (
00861 (((short unsigned int)packet.data[6]) << 8)
00862 | ((short unsigned int)packet.data[7])
00863 ) * 0.01;
00864 ss_ptr->touched = true;
00865 break;
00866 case 0x0403:
00867 ss_ptr->integrated_left_wheel_position =
00868 getInt(packet.data[0], packet.data[1], packet.data[2], packet.data[3])
00869 / this->meters_to_counts_;
00870 ss_ptr->integrated_right_wheel_position =
00871 getInt(packet.data[4], packet.data[5], packet.data[6], packet.data[7])
00872 / this->meters_to_counts_;
00873 ss_ptr->touched = true;
00874 break;
00875 case 0x0404:
00876 ss_ptr->integrated_forward_position =
00877 getInt(packet.data[0], packet.data[1], packet.data[2], packet.data[3])
00878 / this->meters_to_counts_;
00879 ss_ptr->integrated_turn_position =
00880 getInt(packet.data[4], packet.data[5], packet.data[6], packet.data[7])
00881 / this->rev_to_counts_;
00882
00883 ss_ptr->integrated_turn_position *= 360.0;
00884 ss_ptr->touched = true;
00885 break;
00886 case 0x0405:
00887 ss_ptr->left_motor_torque = getShortInt(packet.data[0], packet.data[1])
00888 / this->torque_to_counts_;
00889 ss_ptr->right_motor_torque = getShortInt(packet.data[2], packet.data[3])
00890 / this->torque_to_counts_;
00891 ss_ptr->touched = true;
00892 break;
00893 case 0x0406:
00894 ss_ptr->operational_mode =
00895 OperationalMode(getShortInt(packet.data[0], packet.data[1]));
00896 ss_ptr->controller_gain_schedule =
00897 ControllerGainSchedule(getShortInt(packet.data[2], packet.data[3]));
00898 ss_ptr->ui_battery_voltage =
00899 (
00900 (((short unsigned int)packet.data[4]) << 8)
00901 | ((short unsigned int)packet.data[5])
00902 ) * 0.0125 + 1.4;
00903 ss_ptr->powerbase_battery_voltage =
00904 (
00905 (((short unsigned int)packet.data[6]) << 8)
00906 | ((short unsigned int)packet.data[7])
00907 ) / 4.0;
00908 ss_ptr->touched = true;
00909 break;
00910 case 0x0407:
00911 ss_ptr->commanded_velocity =
00912 (float)getShortInt(packet.data[0], packet.data[1])
00913 / this->mps_to_counts_;
00914 ss_ptr->commanded_yaw_rate =
00915 (float)getShortInt(packet.data[2], packet.data[3])
00916 / 1024.0;
00917 status_updated = true;
00918 ss_ptr->touched = true;
00919 break;
00920 case 0x0680:
00921 if (packet.data[3] == 0x80)
00922 ss_ptr->motor_status = 1;
00923 else
00924 ss_ptr->motor_status = 0;
00925 ss_ptr->touched = true;
00926 break;
00927 default:
00928 break;
00929 };
00930 return status_updated;
00931 }
00932
00933 void SegwayRMP::ProcessPacket_(Packet &packet)
00934 {
00935 bool status_updated = false;
00936
00937 status_updated = this->ParsePacket_(packet, this->segway_status_);
00938
00939
00940
00941
00942 if (status_updated) {
00943 if (this->ss_queue_.enqueue(this->segway_status_)) {
00944 this->error_("Falling behind, SegwayStatus Queue Full, skipping packet "
00945 "report...");
00946 }
00947 this->segway_status_ = SegwayStatus::Ptr(new SegwayStatus());
00948 }
00949 }
00950