00001
00002
00003
00004
00005
00006
00007
00008 #include "DHDDevice.hpp"
00009
00010 #include <telekyb_base/ROS.hpp>
00011 #include <telekyb_base/Time.hpp>
00012
00013
00014
00015 #include <dhdc.h>
00016 #include <boost/lexical_cast.hpp>
00017 using boost::lexical_cast;
00018
00019
00020 #include <tk_haptics_msgs/TKHapticOutput.h>
00021
00022
00023
00024
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
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
00050 nodeHandle = ros::NodeHandle(ROSModule::Instance().getMainNodeHandle(), identifier);
00051
00052
00053 dhdEnableExpertMode();
00054
00055 if (options->tCustomEffectorMass->getValue() >= 0.0) {
00056
00057 ROS_INFO("Setting Custom Effector Mass of %f", options->tCustomEffectorMass->getValue());
00058 dhdSetEffectorMass(options->tCustomEffectorMass->getValue(), id);
00059 }
00060
00061
00062 if (options->tDisableGravityCompensation->getValue()) {
00063 ROS_INFO("Disabling Gravity compenstation.");
00064
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
00076
00077
00078
00079
00080
00081 dhdDisableExpertMode();
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 }
00096
00097 DHDDevice::~DHDDevice()
00098 {
00099
00100 ROS_INFO_STREAM(longIdentifier << ": Closing Device");
00101
00102 dhdClose(id);
00103
00104
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
00122
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
00147 controller->setIdentifier(identifier);
00148
00149
00150 HapticAxesMapping xAxis, yAxis, zAxis;
00151
00152 xAxis = HapticAxesMapping::Forward;
00153 yAxis = HapticAxesMapping::Right;
00154 zAxis = HapticAxesMapping::Up;
00155 controller->setAxesMapping(xAxis, yAxis, zAxis);
00156
00157
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
00170 double px, py, pz;
00171 double oa, ob, og;
00172 double vx, vy, vz;
00173
00174
00175
00176
00177 ROS_INFO_STREAM(longIdentifier << ": Entering spin loop");
00178 controller->willEnterSpinLoop();
00179
00180
00181 Vector3D appliedForce;
00182 Eigen::Matrix3d rotMatix;
00183
00184
00185 Timer outputTimer;
00186 tk_haptics_msgs::TKHapticOutput outputMsg;
00187 outputMsg.header.frame_id = longIdentifier;
00188 while (ros::ok()) {
00189
00190
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
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
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
00226 double outputFreq = options->tStatusOutputFreq->getValue();
00227 if (outputFreq > 0.01 && outputFreq > outputTimer.frequency()) {
00228
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
00248 statusPub.publish(outputMsg);
00249 }
00250 }
00251 controller->didLeaveSpinLoop();
00252 ROS_INFO_STREAM(longIdentifier << ": Leaving spin loop");
00253
00254
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
00271
00272
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
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
00291 currPos << px,py,pz;
00292 currVel << vx,vy,vz;
00293
00294 direction = endPos - currPos;
00295 }
00296 }
00297
00298 }
00299
00300 }
00301