DHDDevice.cpp
Go to the documentation of this file.
00001 /*
00002  * DHDDevice.cpp
00003  *
00004  *  Created on: Sep 29, 2011
00005  *      Author: mriedel
00006  */
00007 
00008 #include "DHDDevice.hpp"
00009 
00010 #include <telekyb_base/ROS.hpp>
00011 #include <telekyb_base/Time.hpp>
00012 
00013 
00014 // 3rd Party
00015 #include <dhdc.h>
00016 #include <boost/lexical_cast.hpp>
00017 using boost::lexical_cast;
00018 
00019 // Status Msg
00020 #include <tk_haptics_msgs/TKHapticOutput.h>
00021 
00022 // move to parameters!
00023 //#define INITIAL_REFRESH_RATE 0.01
00024 //#define DELIMITER "_"
00025 
00026 #define OMEGA_REST_POS_X 0.025
00027 #define OMEGA_REST_POS_Y 0.000
00028 #define OMEGA_REST_POS_Z -0.067
00029 
00030 // 0.8cm
00031 #define OMEGA_REST_MIN_DISTANCE 0.008
00032 #define OMEGA_SHUTDOWN_TIMEOUT_S 4.0
00033 
00034 namespace TELEKYB_NAMESPACE
00035 {
00036 
00037 DHDDevice::DHDDevice(int id_, bool alreadyOpen)
00038         : id(id_), options(NULL), controller(NULL)
00039 {
00040         identifier = lexical_cast<std::string>(id);
00041         options = new DHDDeviceOptions(identifier);
00042 
00043         if (!alreadyOpen) {
00044                 dhdOpenID(id);
00045         }
00046         name = dhdGetSystemName(id);
00047         longIdentifier = "ID: " + lexical_cast<std::string>(id) + " Type: " + name;
00048 
00049         // ROS
00050         nodeHandle = ros::NodeHandle(ROSModule::Instance().getMainNodeHandle(), identifier);
00051 
00052 
00053         dhdEnableExpertMode();
00054 
00055         if (options->tCustomEffectorMass->getValue() >= 0.0) {
00056                 // set custom EffectorMass
00057                 ROS_INFO("Setting Custom Effector Mass of %f", options->tCustomEffectorMass->getValue());
00058                 dhdSetEffectorMass(options->tCustomEffectorMass->getValue(), id);
00059         }
00060 
00061         // Set Option Values
00062         if (options->tDisableGravityCompensation->getValue()) {
00063                 ROS_INFO("Disabling Gravity compenstation.");
00064                 // Disable Compenstation
00065                 dhdSetGravityCompensation(DHD_OFF, id);
00066         } else {
00067                 dhdSetGravityCompensation(DHD_ON, id);
00068         }
00069 
00070         if (options->tEnableForceAtStart->getValue()) {
00071                 ROS_INFO("Enabling Force at Startup");
00072                 dhdEnableForce(DHD_ON, id);
00073         }
00074 
00075         // Test
00076         //dhdReset(id);
00077 //      if (dhdResetWrist(id) == -1) {
00078 //              ROS_ERROR("Unable to initalize Wrist Calibration.");
00079 //      }
00080 
00081         dhdDisableExpertMode();
00082 
00083 
00084         //struct DhdParams dhd33Params = {
00085         //              /*posMin*/ {-0.0475, -0.109, -0.08},
00086         //              /*posMax*/ { 0.071,   0.108,  0.122},
00087         //              /*posRotation*/{
00088         //                      {0.0,1.0,0.0},
00089         //                      {-1.0, 0.0,0.0},
00090         //                      {0.0, 0.0,1.0}
00091         //              },
00092         //              /*noNalibPos*/
00093         //              {0.018, 0.000, -0.073}
00094         //};
00095 }
00096 
00097 DHDDevice::~DHDDevice()
00098 {
00099         // INFO: This doesn't get output anymore, because the node is already shut down. cout would work.
00100         ROS_INFO_STREAM(longIdentifier << ": Closing Device");
00101         //dhdEnableForce(DHD_OFF, id);
00102         dhdClose(id);
00103 
00104         // Delete Controller
00105         if (controller) {
00106                 delete controller;
00107         }
00108 
00109         delete options;
00110 }
00111 
00112 std::string DHDDevice::getLongIdentifier() const
00113 {
00114         return longIdentifier;
00115 }
00116 
00117 void DHDDevice::loadController(pluginlib::ClassLoader<HapticDeviceController>& controllerLoader)
00118 {
00119         try {
00120                 controller = controllerLoader.createClassInstance(options->tHapticDeviceController->getValue());
00121                 // success
00122                 //ROS_INFO_STREAM("Successfully loaded Behavior: " << behaviorClassName << ", Instance: " << (long)b);
00123         } catch (pluginlib::PluginlibException &e) {
00124                 ROS_ERROR_STREAM("HapticDeviceController Plugin "
00125                                 << options->tHapticDeviceController->getValue() << " failed to load. Message: " << e.what());
00126         }
00127 
00128 }
00129 
00130 void DHDDevice::startThread()
00131 {
00132         thread = boost::thread(&DHDDevice::spin, this);
00133 }
00134 
00135 void DHDDevice::joinThread()
00136 {
00137         thread.join();
00138 }
00139 
00140 bool DHDDevice::init()
00141 {
00142         if (!controller) {
00143                 ROS_ERROR("Cannot enter spinloop without a HapticDeviceController");
00144                 return false;
00145         }
00146         // Send initializer
00147         controller->setIdentifier(identifier);
00148 
00149         // Do controller Init
00150         HapticAxesMapping xAxis, yAxis, zAxis;
00151         // Axes for DHD Devices
00152         xAxis = HapticAxesMapping::Forward;
00153         yAxis = HapticAxesMapping::Right;
00154         zAxis = HapticAxesMapping::Up;
00155         controller->setAxesMapping(xAxis, yAxis, zAxis);
00156 
00157         // create Publisher
00158         statusPub = nodeHandle.advertise<tk_haptics_msgs::TKHapticOutput>(options->tStatusOutputTopic->getValue(), 10);
00159 
00160         return true;
00161 }
00162 
00163 void DHDDevice::spin()
00164 {
00165         if (!init()) {
00166                 return;
00167         }
00168 
00169         // DHD Parameters out / spin
00170         double px, py, pz;
00171         double oa, ob, og;
00172         double vx, vy, vz;
00173         //double ifx, ify, ifz;
00174         //double ita, itb, itg;
00175 
00176 
00177         ROS_INFO_STREAM(longIdentifier << ": Entering spin loop");
00178         controller->willEnterSpinLoop();
00179 
00180         // Loop Variables
00181         Vector3D appliedForce;
00182         Eigen::Matrix3d rotMatix;
00183 
00184         // For StatusOutput
00185         Timer outputTimer;
00186         tk_haptics_msgs::TKHapticOutput outputMsg;
00187         outputMsg.header.frame_id = longIdentifier;
00188         while (ros::ok()) {
00189 
00190                 // write down position
00191                 if (dhdGetPositionAndOrientationRad(&px, &py, &pz, &oa, &ob, &og, id) < 0) {
00192                         ROS_ERROR_STREAM(longIdentifier <<": Cannot read position and/or orientation: " << dhdErrorGetLastStr());
00193                         break;
00194                 }
00195 
00196                 if (dhdGetLinearVelocity(&vx, &vy, &vz, id) < 0) {
00197                         ROS_ERROR_STREAM(longIdentifier <<": Cannot get linear velocity estimate: " << dhdErrorGetLastStr());
00198                         break;
00199                 }
00200 
00201                 // Generate Output
00202 
00203                 rotMatix =
00204                                 Eigen::AngleAxisd(oa, Eigen::Vector3d::UnitX()) *
00205                                 Eigen::AngleAxisd(ob, Eigen::Vector3d::UnitY()) *
00206                                 Eigen::AngleAxisd(og, Eigen::Vector3d::UnitZ());
00207 
00208                 output.position = Position3D(px,py,pz) - options->tCenterTranslation->getValue();
00209                 output.linVelocity = Velocity3D(vx, vy, vz);
00210                 output.orientation = Quaternion(rotMatix);
00211                 output.force = input.force;
00212                 output.frequency = dhdGetComFreq(id) * 1000;
00213                 output.primaryButton = dhdGetButton(0, id);
00214 
00215                 // loop CB
00216                 controller->loopCB(output, input);
00217 
00218                 appliedForce = input.force + options->tForceOffset->getValue();
00219 
00220                 if (dhdSetForce(appliedForce(0), appliedForce(1), appliedForce(2), id) < DHD_NO_ERROR) {
00221                         ROS_ERROR_STREAM(identifier << ": Cannot set force: " << dhdErrorGetLastStr());
00222                         break;
00223                 }
00224 
00225                 // send out status?
00226                 double outputFreq = options->tStatusOutputFreq->getValue();
00227                 if (outputFreq > 0.01 && outputFreq > outputTimer.frequency()) {
00228                         // reset
00229                         outputTimer.reset();
00230 
00231                         outputMsg.header.stamp = ros::Time::now();
00232                         outputMsg.force.x = input.force(0);
00233                         outputMsg.force.y = input.force(1);
00234                         outputMsg.force.z = input.force(2);
00235                         outputMsg.frequency = output.frequency;
00236                         outputMsg.linear.x = output.linVelocity(0);
00237                         outputMsg.linear.y = output.linVelocity(1);
00238                         outputMsg.linear.z = output.linVelocity(2);
00239                         outputMsg.pose.position.x = output.position(0);
00240                         outputMsg.pose.position.y = output.position(1);
00241                         outputMsg.pose.position.z = output.position(2);
00242                         outputMsg.pose.orientation.w = output.orientation.w();
00243                         outputMsg.pose.orientation.x = output.orientation.x();
00244                         outputMsg.pose.orientation.y = output.orientation.y();
00245                         outputMsg.pose.orientation.z = output.orientation.z();
00246                         outputMsg.primaryButton = output.primaryButton;
00247                         // publish
00248                         statusPub.publish(outputMsg);
00249                 }
00250         }
00251         controller->didLeaveSpinLoop();
00252         ROS_INFO_STREAM(longIdentifier << ": Leaving spin loop");
00253 
00254         // Gentle Shutdown for legacy OMEGA.
00255         if (dhdGetSystemType(id) == DHD_DEVICE_OMEGA) {
00256 
00257                 Timer timeout;
00258 
00259                 Position3D endPos(OMEGA_REST_POS_X, OMEGA_REST_POS_Y, OMEGA_REST_POS_Z);
00260 
00261                 Position3D currPos(px,py,pz);
00262                 Velocity3D currVel(vx,vy,vz);
00263                 double posGain = 70.0;
00264                 double velGain = 30.0;
00265                 Position3D direction = endPos - currPos;
00266                 while (direction.norm() > OMEGA_REST_MIN_DISTANCE && timeout.getElapsed().toDSec() < OMEGA_SHUTDOWN_TIMEOUT_S) {
00267 
00268 
00269                         Vector3D force = posGain*direction - velGain*currVel;
00270                         //std::cout << "OMEGA applying: " << std::endl << force << std::endl;
00271                         //force = Vector3D(0.0, 0.0, 0.0);
00272                         // apply force
00273                         if (dhdSetForce(force(0), force(1), force(2), id) < DHD_NO_ERROR) {
00274                                 std::cerr << identifier << ": Cannot set force: " << dhdErrorGetLastStr() << std::endl;
00275                                 break;
00276                         }
00277 
00278 
00279                         // write new position
00280                         if (dhdGetPositionAndOrientationRad(&px, &py, &pz, &oa, &ob, &og, id) < 0) {
00281                                 std::cerr << longIdentifier <<": Cannot read position and/or orientation: " << dhdErrorGetLastStr() << std::endl;
00282                                 break;
00283                         }
00284 
00285                         if (dhdGetLinearVelocity(&vx, &vy, &vz, id) < 0) {
00286                                 std::cerr << longIdentifier <<": Cannot get linear velocity estimate: " << dhdErrorGetLastStr() << std::endl;
00287                                 break;
00288                         }
00289 
00290                         // update.
00291                         currPos << px,py,pz;
00292                         currVel << vx,vy,vz;
00293 
00294                         direction = endPos - currPos;
00295                 }
00296         }
00297 
00298 }
00299 
00300 } // Namespace
00301 
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Friends Defines


dhd32_driver
Author(s): Martin Riedel
autogenerated on Mon Nov 11 2013 11:14:43