omni.cpp
Go to the documentation of this file.
00001 #include <ros/ros.h>
00002 #include <geometry_msgs/PoseStamped.h>
00003 #include <tf/transform_broadcaster.h>
00004 #include <geometry_msgs/Wrench.h>
00005 #include <geometry_msgs/WrenchStamped.h>
00006 
00007 #include <string.h>
00008 #include <stdio.h>
00009 #include <math.h>
00010 #include <assert.h>
00011 #include <sstream>
00012 
00013 #include <HL/hl.h>
00014 #include <HD/hd.h>
00015 #include <HDU/hduError.h>
00016 #include <HDU/hduVector.h>
00017 #include <HDU/hduMatrix.h>
00018 
00019 #include "phantom_omni/PhantomButtonEvent.h"
00020 #include "phantom_omni/OmniFeedback.h"
00021 #include <pthread.h>
00022 
00023 float prev_time;
00024 
00025 struct OmniState
00026 {
00027     hduVector3Dd position;  //3x1 vector of position
00028     hduVector3Dd velocity;  //3x1 vector of velocity
00029     hduVector3Dd inp_vel1;  //3x1 history of velocity used for filtering velocity estimate
00030     hduVector3Dd inp_vel2;  
00031     hduVector3Dd inp_vel3;  
00032     hduVector3Dd out_vel1;  
00033     hduVector3Dd out_vel2;  
00034     hduVector3Dd out_vel3;
00035     hduVector3Dd pos_hist1; //3x1 history of position used for 2nd order backward difference estimate of velocity 
00036     hduVector3Dd pos_hist2; 
00037     hduVector3Dd rot;
00038     hduVector3Dd joints;
00039     hduVector3Dd force;     //3 element double vector force[0], force[1], force[2]
00040     float thetas[7];
00041     int buttons[2];
00042     int buttons_prev[2];
00043     bool lock;
00044     hduVector3Dd lock_pos;
00045 };
00046 
00047 
00048 class PhantomROS {
00049 
00050         public:
00051         ros::NodeHandle n;
00052         ros::Publisher pose_publisher;
00053         //ros::Publisher omni_pose_publisher;
00054 
00055     ros::Publisher button_publisher;
00056         ros::Subscriber haptic_sub;
00057     std::string omni_name;
00058     std::string sensable_frame_name;
00059     std::string link_names[7];
00060 
00061     OmniState *state;
00062     tf::TransformBroadcaster br;
00063 
00064     void init(OmniState *s) 
00065     {
00066         ros::param::param(std::string("~omni_name"), omni_name, std::string("omni1"));
00067 
00068         //Publish on NAME_pose
00069         std::ostringstream stream00;
00070         stream00 << omni_name << "_pose";
00071         std::string pose_topic_name = std::string(stream00.str());
00072         pose_publisher = n.advertise<geometry_msgs::PoseStamped>(pose_topic_name.c_str(), 100);
00073         //omni_pose_publisher = n.advertise<geometry_msgs::PoseStamped>("omni_pose_internal", 100);
00074 
00075         //Publish button state on NAME_button
00076         std::ostringstream stream0;
00077         stream0 << omni_name << "_button";
00078         std::string button_topic = std::string(stream0.str());
00079         button_publisher = n.advertise<phantom_omni::PhantomButtonEvent>(button_topic.c_str(), 100);
00080 
00081         //Subscribe to NAME_force_feedback
00082         std::ostringstream stream01;
00083         stream01 << omni_name << "_force_feedback";
00084         std::string force_feedback_topic = std::string(stream01.str());
00085         haptic_sub = n.subscribe(force_feedback_topic.c_str(), 100, &PhantomROS::force_callback, this);
00086 
00087         //Frame of force feedback (NAME_sensable)
00088         std::ostringstream stream2;
00089         stream2 << omni_name << "_sensable";
00090         sensable_frame_name = std::string(stream2.str());
00091 
00092         for (int i = 0; i < 7; i++)
00093         {
00094             std::ostringstream stream1;
00095             stream1 << omni_name << "_link" << i;
00096             link_names[i] = std::string(stream1.str());
00097         }
00098 
00099 
00100         state = s;
00101         state->buttons[0] = 0;
00102         state->buttons[1] = 0;
00103         state->buttons_prev[0] = 0;
00104         state->buttons_prev[1] = 0;
00105         hduVector3Dd zeros(0, 0, 0);
00106         state->velocity = zeros;
00107         state->inp_vel1 = zeros;  //3x1 history of velocity
00108         state->inp_vel2 = zeros;  //3x1 history of velocity
00109         state->inp_vel3 = zeros;  //3x1 history of velocity
00110         state->out_vel1 = zeros;  //3x1 history of velocity
00111         state->out_vel2 = zeros;  //3x1 history of velocity
00112         state->out_vel3 = zeros;  //3x1 history of velocity
00113         state->pos_hist1 = zeros; //3x1 history of position 
00114         state->pos_hist2 = zeros; //3x1 history of position
00115         state->lock = true;
00116         state->lock_pos = zeros;
00117     }
00118 
00119     /*******************************************************************************
00120      ROS node callback.  
00121     *******************************************************************************/
00122   //    void force_callback(const geometry_msgs::WrenchConstPtr& wrench)
00123     void force_callback(const phantom_omni::OmniFeedbackConstPtr& omnifeed)
00124     {
00129         state->force[0] = omnifeed->force.x - 0.001*state->velocity[0];
00130         state->force[1] = omnifeed->force.y - 0.001*state->velocity[1];
00131         state->force[2] = omnifeed->force.z - 0.001*state->velocity[2];
00132 
00133         state->lock_pos[0] = omnifeed->position.x;
00134         state->lock_pos[1] = omnifeed->position.y;
00135         state->lock_pos[2] = omnifeed->position.z;
00136         //        state->force[2] = wrench->force.z;
00137     } 
00138 
00139     void publish_omni_state()
00140     {
00141         //Construct transforms
00142         tf::Transform l0, sensable, l1, l2, l3, l4, l5, l6, l0_6;
00143         l0.setOrigin(tf::Vector3(0., 0, 0.15));
00144         l0.setRotation(tf::Quaternion(0, 0, 0));
00145         br.sendTransform(tf::StampedTransform(l0, ros::Time::now(), omni_name.c_str(), link_names[0].c_str()));
00146 
00147         sensable.setOrigin(tf::Vector3(0., 0, 0));
00148         sensable.setRotation(tf::Quaternion(-M_PI/2, 0, M_PI/2));
00149         br.sendTransform(tf::StampedTransform(sensable, ros::Time::now(), 
00150                         omni_name.c_str(), sensable_frame_name.c_str()));
00151 
00152         l1.setOrigin(tf::Vector3(0., 0, 0.));
00153         l1.setRotation(tf::Quaternion(-state->thetas[1], 0, 0));
00154                                                                                                           
00155         l2.setOrigin(tf::Vector3(0., 0, 0.));                                                           
00156         l2.setRotation(tf::Quaternion(0, state->thetas[2], 0));                                         
00157                                                                                                           
00158         l3.setOrigin(tf::Vector3(-.131, 0, 0.));                                                        
00159         l3.setRotation(tf::Quaternion(0, state->thetas[3], 0));                            
00160                                                                                                           
00161         l4.setOrigin(tf::Vector3(0., 0, -.137));                                                        
00162         l4.setRotation(tf::Quaternion(state->thetas[4]+M_PI, 0, 0));                       
00163                                                                                                           
00164         l5.setOrigin(tf::Vector3(0., 0., 0.));                                                          
00165         l5.setRotation(tf::Quaternion(0., -state->thetas[5]+M_PI,0));                      
00166 
00167         l6.setOrigin(tf::Vector3(0., 0., 0.));
00168         l6.setRotation(tf::Quaternion(0.,0, state->thetas[6]+M_PI));
00169         
00170         l0_6 = l0 * l1 * l2 * l3 * l4 * l5 * l6;
00171         br.sendTransform(tf::StampedTransform(l0_6, ros::Time::now(), link_names[0].c_str(), link_names[6].c_str()));
00172         //Don't send these as they slow down haptics thread
00173         //br.sendTransform(tf::StampedTransform(l1, ros::Time::now(), link_names[0].c_str(), link_names[1].c_str()));
00174         //br.sendTransform(tf::StampedTransform(l2, ros::Time::now(), link_names[1].c_str(), link_names[2].c_str()));
00175         //br.sendTransform(tf::StampedTransform(l3, ros::Time::now(), link_names[2].c_str(), link_names[3].c_str()));
00176         //br.sendTransform(tf::StampedTransform(l4, ros::Time::now(), link_names[3].c_str(), link_names[4].c_str()));
00177         //br.sendTransform(tf::StampedTransform(l5, ros::Time::now(), link_names[4].c_str(), link_names[5].c_str()));
00178         //br.sendTransform(tf::StampedTransform(link, ros::Time::now(), link_names[5].c_str(), link_names[6].c_str()));
00179         
00180         //Sample 'end effector' pose
00181         geometry_msgs::PoseStamped pose_stamped;
00182         pose_stamped.header.frame_id = link_names[6].c_str();
00183         pose_stamped.header.stamp = ros::Time::now();
00184         pose_stamped.pose.position.x = 0.0;   //was 0.03 to end of phantom
00185         pose_stamped.pose.orientation.w = 1.;
00186         pose_publisher.publish(pose_stamped);
00187 
00188         //geometry_msgs::PoseStamped omni_internal_pose;
00189         //omni_internal_pose.header.frame_id = "sensable";
00190         //omni_internal_pose.header.stamp = ros::Time::now();
00191         //omni_internal_pose.pose.position.x = state->position[0]/1000.0;
00192         //omni_internal_pose.pose.position.y = state->position[1]/1000.0;
00193         //omni_internal_pose.pose.position.z = state->position[2]/1000.0;
00194         //omni_pose_publisher.publish(omni_internal_pose);
00195 
00196         if ((state->buttons[0] != state->buttons_prev[0]) or (state->buttons[1] != state->buttons_prev[1]))
00197         {
00198             
00199           if ((state->buttons[0] == state->buttons[1]) and (state->buttons[0] == 1))
00200             {
00201               state->lock = !(state->lock);
00202             }
00203             phantom_omni::PhantomButtonEvent button_event;
00204             button_event.grey_button = state->buttons[0];
00205             button_event.white_button = state->buttons[1];
00206             state->buttons_prev[0] = state->buttons[0];
00207             state->buttons_prev[1] = state->buttons[1];
00208             button_publisher.publish(button_event);
00209         }
00210     }
00211 };
00212 
00213 HDCallbackCode HDCALLBACK omni_state_callback(void *pUserData)
00214 {
00215     OmniState *omni_state = static_cast<OmniState *>(pUserData);
00216 
00217     
00218         hdBeginFrame(hdGetCurrentDevice());
00219     //Get angles, set forces
00220         hdGetDoublev(HD_CURRENT_GIMBAL_ANGLES, omni_state->rot);      
00221         hdGetDoublev(HD_CURRENT_POSITION,      omni_state->position);
00222         hdGetDoublev(HD_CURRENT_JOINT_ANGLES,  omni_state->joints);
00223 
00224         hduVector3Dd vel_buff(0, 0, 0);
00225         vel_buff = (omni_state->position*3 - 4*omni_state->pos_hist1 + omni_state->pos_hist2)/0.002;  //mm/s, 2nd order backward dif
00226         //      omni_state->velocity = 0.0985*(vel_buff+omni_state->inp_vel3)+0.2956*(omni_state->inp_vel1+omni_state->inp_vel2)-(-0.5772*omni_state->out_vel1+0.4218*omni_state->out_vel2 - 0.0563*omni_state->out_vel3);    //cutoff freq of 200 Hz
00227         omni_state->velocity = (.2196*(vel_buff+omni_state->inp_vel3)+.6588*(omni_state->inp_vel1+omni_state->inp_vel2))/1000.0-(-2.7488*omni_state->out_vel1+2.5282*omni_state->out_vel2 - 0.7776*omni_state->out_vel3);  //cutoff freq of 20 Hz
00228         omni_state->pos_hist2 = omni_state->pos_hist1;
00229         omni_state->pos_hist1 = omni_state->position;
00230         omni_state->inp_vel3 = omni_state->inp_vel2;
00231         omni_state->inp_vel2 = omni_state->inp_vel1;
00232         omni_state->inp_vel1 = vel_buff;
00233         omni_state->out_vel3 = omni_state->out_vel2;
00234         omni_state->out_vel2 = omni_state->out_vel1;
00235         omni_state->out_vel1 = omni_state->velocity;
00236         //      printf("position x, y, z: %f %f %f \n", omni_state->position[0], omni_state->position[1], omni_state->position[2]);
00237         //      printf("velocity x, y, z, time: %f %f %f \n", omni_state->velocity[0], omni_state->velocity[1],omni_state->velocity[2]);
00238         if (omni_state->lock == true)
00239           {
00240             omni_state->force = 0.04*(omni_state->lock_pos-omni_state->position) - 0.001*omni_state->velocity;      
00241           }
00242 
00243         hdSetDoublev(HD_CURRENT_FORCE,         omni_state->force);
00244         
00245     //Get buttons
00246     int nButtons = 0;
00247     hdGetIntegerv(HD_CURRENT_BUTTONS, &nButtons);
00248     omni_state->buttons[0] = (nButtons & HD_DEVICE_BUTTON_1) ? 1 : 0;
00249     omni_state->buttons[1] = (nButtons & HD_DEVICE_BUTTON_2) ? 1 : 0;
00250 
00251         hdEndFrame(hdGetCurrentDevice());
00252 
00253     HDErrorInfo error;
00254     if (HD_DEVICE_ERROR(error = hdGetError()))
00255     {
00256                 hduPrintError(stderr, &error, "Error during main scheduler callback\n");
00257                 if (hduIsSchedulerError(&error))
00258                         return HD_CALLBACK_DONE;
00259     }
00260 
00261     float t[7] = {0., omni_state->joints[0], omni_state->joints[1], omni_state->joints[2]-omni_state->joints[1], 
00262                       omni_state->rot[0],    omni_state->rot[1],    omni_state->rot[2]};
00263     for (int i = 0; i < 7; i++)
00264         omni_state->thetas[i] = t[i];
00265     return HD_CALLBACK_CONTINUE;
00266 }
00267 
00268 /*******************************************************************************
00269 Automatic Calibration of Phantom Device - No character inputs
00270 *******************************************************************************/
00271 void HHD_Auto_Calibration()
00272 {
00273    int calibrationStyle;
00274    int supportedCalibrationStyles;
00275    HDErrorInfo error;
00276 
00277    hdGetIntegerv(HD_CALIBRATION_STYLE, &supportedCalibrationStyles);
00278    if (supportedCalibrationStyles & HD_CALIBRATION_ENCODER_RESET)
00279    {
00280                 calibrationStyle = HD_CALIBRATION_ENCODER_RESET;
00281                 ROS_INFO("HD_CALIBRATION_ENCODER_RESE..\n\n");
00282    }
00283    if (supportedCalibrationStyles & HD_CALIBRATION_INKWELL)
00284    {
00285                 calibrationStyle = HD_CALIBRATION_INKWELL;
00286                 ROS_INFO("HD_CALIBRATION_INKWELL..\n\n");
00287    }
00288    if (supportedCalibrationStyles & HD_CALIBRATION_AUTO)
00289    {
00290        calibrationStyle = HD_CALIBRATION_AUTO;
00291        ROS_INFO("HD_CALIBRATION_AUTO..\n\n");
00292    }
00293 
00294    do 
00295    {
00296            hdUpdateCalibration(calibrationStyle);
00297            ROS_INFO("Calibrating.. (put stylus in well)\n");
00298        if (HD_DEVICE_ERROR(error = hdGetError()))
00299        {
00300                hduPrintError(stderr, &error, "Reset encoders reset failed.");
00301                break;           
00302            }
00303    }   while (hdCheckCalibration() != HD_CALIBRATION_OK);
00304 
00305    ROS_INFO("\n\nCalibration complete.\n");
00306 }
00307 
00308 void *ros_publish(void *ptr)
00309 {
00310    PhantomROS *omni_ros = (PhantomROS *) ptr;
00311    int publish_rate;
00312    omni_ros->n.param(std::string("publish_rate"), publish_rate, 100);
00313    ros::Rate loop_rate(publish_rate);
00314    ros::AsyncSpinner spinner(2);
00315    spinner.start();
00316 
00317    while(ros::ok())
00318    {
00319        omni_ros->publish_omni_state();
00320        loop_rate.sleep();
00321    }
00322    return NULL;
00323 }
00324 
00325 int main(int argc, char** argv)
00326 {
00328    // Init Phantom
00330    HDErrorInfo error;
00331    HHD hHD;
00332    hHD = hdInitDevice(HD_DEFAULT_DEVICE);
00333    if (HD_DEVICE_ERROR(error = hdGetError())) 
00334    {
00335        //hduPrintError(stderr, &error, "Failed to initialize haptic device");
00336        ROS_ERROR("Failed to initialize haptic device"); //: %s", &error);
00337        return -1;
00338    }
00339 
00340    ROS_INFO("Found %s.\n\n", hdGetString(HD_DEVICE_MODEL_TYPE));
00341    hdEnable(HD_FORCE_OUTPUT);
00342    hdStartScheduler(); 
00343    if (HD_DEVICE_ERROR(error = hdGetError()))
00344    {
00345        ROS_ERROR("Failed to start the scheduler");//, &error);
00346        return -1;           
00347    }
00348    HHD_Auto_Calibration();
00349 
00351    // Init ROS 
00353    ros::init(argc, argv, "omni_haptic_node");
00354    OmniState state;
00355    PhantomROS omni_ros;
00356 
00357    omni_ros.init(&state);
00358    hdScheduleAsynchronous(omni_state_callback, &state, HD_MAX_SCHEDULER_PRIORITY);
00359 
00361    // Loop and publish 
00363    pthread_t publish_thread;
00364    pthread_create(&publish_thread, NULL, ros_publish, (void*) &omni_ros);
00365    pthread_join(publish_thread, NULL);
00366 
00367    ROS_INFO("Ending Session....\n");
00368    hdStopScheduler();
00369    hdDisableDevice(hHD);
00370 
00371    return 0;
00372 }
00373 
00374 


phantom_omni
Author(s): Hai Nguyen, Marc Killpack, Chi-Hung King, Advisor: Prof. Charlie Kemp, Lab: Healthcare Robotics Lab at Georgia Tech
autogenerated on Wed Nov 27 2013 11:51:14