kinect_teleop.cpp
Go to the documentation of this file.
00001 
00008 // General Includes
00009 #include <math.h>
00010 #include <vector>
00011 
00012 // ROS Includes
00013 #include <ros/ros.h>
00014 #include <ros/package.h>
00015 #include <pr2_controllers_msgs/JointTrajectoryAction.h>
00016 #include <actionlib/client/simple_action_client.h>
00017 #include <tf/transform_broadcaster.h>
00018 #include <kdl/frames.hpp>
00019 
00020 #include <std_msgs/String.h> 
00021 #include <geometry_msgs/Twist.h> 
00022 
00023 // Eigen includes
00024 #include <Eigen/Core>
00025 
00026 // Prime Sense Includes
00027 #include <XnOpenNI.h>
00028 #include <XnCodecIDs.h>
00029 #include <XnCppWrapper.h>
00030 
00031 #define my_pi 3.141592653589793
00032 
00033 using std::string;
00034 
00035 typedef actionlib::SimpleActionClient<pr2_controllers_msgs::JointTrajectoryAction> TrajClient;
00036 typedef std::vector<std::pair<Eigen::VectorXd, Eigen::VectorXd> > Trajectory;
00037 TrajClient *arm_client_r;
00038 TrajClient *arm_client_l;
00039 
00040 // Prime Sense related
00041 xn::Context g_Context;
00042 xn::DepthGenerator g_DepthGenerator;
00043 xn::UserGenerator g_UserGenerator;
00044 
00045 XnPoint3D init_usr_loc;
00046 XnPoint3D init_usr_RS; // Initial location of the user's Right Shoulder (for rotation of the body)
00047 XnPoint3D init_usr_LS; // Initial location of the user's Left Shoulder (for rotation of the body)
00048 
00049 XnBool g_bNeedPose = FALSE;
00050 XnChar g_strPose[20] = "";
00051 
00052 // OpenNI Check Fault
00053 #define CHECK_RC(nRetVal, what)                                         \
00054   if (nRetVal != XN_STATUS_OK)                                          \
00055     {                                                                   \
00056       printf("%s failed: %s\n", what, xnGetStatusString(nRetVal));      \
00057       return nRetVal;                                                   \
00058     }
00059 
00060 
00061 struct pr2_joint
00062 {
00063   float yaw;
00064   float pitch;
00065   float absolute;
00066 };
00067 
00068 class TeleopPR2Ni
00069 {
00070 
00071 public:
00072   EIGEN_MAKE_ALIGNED_OPERATOR_NEW
00073 
00074   TeleopPR2Ni();
00075   void
00076   updateTrajectory(double rate);
00077   void
00078   pubMsg(double rate);
00079   void
00080   initangles(pr2_joint &joint);
00081   void
00082   updateTrajectoryFromJoints(Trajectory &trajectory, pr2_joint &shoulderAngles,
00083       pr2_joint &elbowAngles, Eigen::VectorXd &curr_pos, Eigen::VectorXd &last_pos, double rate);
00084   void
00085   fillGoal(pr2_controllers_msgs::JointTrajectoryGoal &goal, Trajectory &trajectory, double rate);
00086 
00087   ros::NodeHandle nh_; // Node that will publish messages
00088   ros::NodeHandle privateNh_; // Initialized but not used in this code. Inherited from Albert-Ludwig University's implementation
00089 
00090   bool enabled_;
00091   bool teleopEnabled_; // Teleoperation enabled - Body Control (mutually exclusive with attentionEnabled)
00092   bool useLeftArm_;
00093   ros::Publisher rShoulderPub_; //           right shoulder angles
00094   ros::Publisher rElbowPub_; //           right elbow angles
00095   ros::Publisher lShoulderPub_; //           right shoulder angles
00096   ros::Publisher lElbowPub_; //           right elbow angles
00097 
00098   pr2_joint rShoulderAngles_; // Right shoulder angles
00099   pr2_joint rElbowAngles_; // Right elbow angles
00100   pr2_joint lShoulderAngles_; // Left shoulder angles
00101   pr2_joint lElbowAngles_; // Left elbow angles
00102 
00103   Eigen::VectorXd curr_pos_r_;
00104   Eigen::VectorXd last_pos_r_;
00105   Eigen::VectorXd curr_pos_l_;
00106   Eigen::VectorXd last_pos_l_;
00107 
00108   Trajectory trajectory_r_;
00109   Trajectory trajectory_l_;
00110 };
00111 
00112 // Initialization list of object teleopPR2Ni
00113 TeleopPR2Ni::TeleopPR2Ni() :
00114   privateNh_("~"), teleopEnabled_(false)
00115 {
00116   enabled_ = true;
00117 
00118   // Initialize all velocities and angles at zero.
00119   initangles(rShoulderAngles_);
00120   initangles(rElbowAngles_);
00121   initangles(lShoulderAngles_);
00122   initangles(lElbowAngles_);
00123   // init positions
00124   curr_pos_r_.setZero(4);
00125   last_pos_r_.setZero(4);
00126   curr_pos_l_.setZero(4);
00127   last_pos_l_.setZero(4);
00128 }
00129 
00130 void
00131 TeleopPR2Ni::initangles(pr2_joint &joint)
00132 {
00133   // Initialize all velocities and angles at zero.
00134   joint.yaw = 0.0;
00135   joint.pitch = 0.0;
00136   joint.absolute = 1.0;
00137 }
00138 
00139 void
00140 TeleopPR2Ni::updateTrajectoryFromJoints(Trajectory &trajectory, pr2_joint &shoulderAngles,
00141     pr2_joint &elbowAngles, Eigen::VectorXd &curr_pos, Eigen::VectorXd &last_pos, double rate)
00142 {
00143   Eigen::VectorXd next_pos(4);
00144   Eigen::VectorXd next_vel(4);
00145 
00146   next_pos(0) = shoulderAngles.yaw;
00147   next_pos(1) = shoulderAngles.pitch;
00148   next_pos(2) = elbowAngles.yaw;
00149   next_pos(3) = -elbowAngles.pitch;
00150 
00151   next_vel = (next_pos - last_pos) / (2. * (1. / rate));
00152 
00153   if ((next_pos - curr_pos).norm() > 1. * my_pi / 180.)
00154     {
00155       trajectory.push_back(std::make_pair<Eigen::VectorXd, Eigen::VectorXd>(next_pos, next_vel));
00156       last_pos = curr_pos;
00157       curr_pos = next_pos;
00158     }
00159   else
00160     {
00161       last_pos = curr_pos;
00162       next_vel.setZero(4);
00163       trajectory.push_back(std::make_pair<Eigen::VectorXd, Eigen::VectorXd>(curr_pos, next_vel));
00164     }
00165 }
00166 
00167 void
00168 TeleopPR2Ni::updateTrajectory(double rate)
00169 {
00170   updateTrajectoryFromJoints(trajectory_r_, rShoulderAngles_, rElbowAngles_, curr_pos_r_,
00171       last_pos_r_, rate);
00172   updateTrajectoryFromJoints(trajectory_l_, lShoulderAngles_, lElbowAngles_, curr_pos_l_,
00173       last_pos_l_, rate);
00174 }
00175 
00176 void
00177 TeleopPR2Ni::fillGoal(pr2_controllers_msgs::JointTrajectoryGoal &goal, Trajectory &trajectory,
00178     double rate)
00179 {
00180   // We will have two waypoints in this goal trajectory
00181   goal.trajectory.points.resize(trajectory.size());
00182   for (size_t ind = 0; ind < trajectory.size(); ++ind)
00183     {
00184       Eigen::VectorXd &pos = trajectory[ind].first;
00185       Eigen::VectorXd &vel = trajectory[ind].second;
00186       // Positions
00187       goal.trajectory.points[ind].positions.resize(7);
00188       goal.trajectory.points[ind].positions[0] = pos(0);
00189       goal.trajectory.points[ind].positions[1] = pos(1);
00190       goal.trajectory.points[ind].positions[2] = pos(2);
00191       goal.trajectory.points[ind].positions[3] = pos(3);
00192       goal.trajectory.points[ind].positions[4] = 0.0;
00193       goal.trajectory.points[ind].positions[5] = 0.0;
00194       goal.trajectory.points[ind].positions[6] = 0.0;
00195 
00196       // Velocities
00197       vel /= 50.;
00198       goal.trajectory.points[ind].velocities.resize(7);
00199       goal.trajectory.points[ind].velocities[0] = vel(0);
00200       goal.trajectory.points[ind].velocities[1] = vel(1);
00201       goal.trajectory.points[ind].velocities[2] = vel(2);
00202       goal.trajectory.points[ind].velocities[3] = vel(3);
00203       goal.trajectory.points[ind].velocities[4] = 0.0;
00204       goal.trajectory.points[ind].velocities[5] = 0.0;
00205       goal.trajectory.points[ind].velocities[6] = 0.0;
00206       // To be reached 1 second after starting along the trajectory
00207       goal.trajectory.points[ind].time_from_start = ros::Duration((ind + 1) * (1 / rate));
00208     }
00209 
00210   //ROS_INFO("Sending goal");
00211 }
00212 
00213 void
00214 TeleopPR2Ni::pubMsg(double rate)
00215 {
00216   if (teleopEnabled_ && arm_client_r && trajectory_r_.size() >= 3)
00217     { // RIGHT ARM
00218       pr2_controllers_msgs::JointTrajectoryGoal goal;
00219       goal.trajectory.header.stamp = ros::Time::now();
00220       // First, the joint names, which apply to all waypoints
00221       goal.trajectory.joint_names.push_back("r_shoulder_pan_joint");
00222       goal.trajectory.joint_names.push_back("r_shoulder_lift_joint");
00223       goal.trajectory.joint_names.push_back("r_upper_arm_roll_joint");
00224       goal.trajectory.joint_names.push_back("r_elbow_flex_joint");
00225       goal.trajectory.joint_names.push_back("r_forearm_roll_joint");
00226       goal.trajectory.joint_names.push_back("r_wrist_flex_joint");
00227       goal.trajectory.joint_names.push_back("r_wrist_roll_joint");
00228 
00229       fillGoal(goal, trajectory_r_, rate);
00230 
00231       arm_client_r->sendGoal(goal);
00232       trajectory_r_.clear();
00233     }
00234   if (teleopEnabled_ && useLeftArm_ && arm_client_l && trajectory_l_.size() >= 3)
00235     { // LEFT ARM
00236       pr2_controllers_msgs::JointTrajectoryGoal goal;
00237       goal.trajectory.header.stamp = ros::Time::now() + ros::Duration(1 / rate);
00238       // First, the joint names, which apply to all waypoints
00239       goal.trajectory.joint_names.push_back("l_shoulder_pan_joint");
00240       goal.trajectory.joint_names.push_back("l_shoulder_lift_joint");
00241       goal.trajectory.joint_names.push_back("l_upper_arm_roll_joint");
00242       goal.trajectory.joint_names.push_back("l_elbow_flex_joint");
00243       goal.trajectory.joint_names.push_back("l_forearm_roll_joint");
00244       goal.trajectory.joint_names.push_back("l_wrist_flex_joint");
00245       goal.trajectory.joint_names.push_back("l_wrist_roll_joint");
00246 
00247       fillGoal(goal, trajectory_l_, rate);
00248 
00249       arm_client_l->sendGoal(goal);
00250       trajectory_l_.clear();
00251     }
00252 }
00253 
00254 void XN_CALLBACK_TYPE User_NewUser(xn::UserGenerator& generator, XnUserID nId, void* pCookie)
00255   {
00256     printf("New User %d\n", nId);
00257     if (g_bNeedPose)
00258     g_UserGenerator.GetPoseDetectionCap().StartPoseDetection(g_strPose, nId);
00259     else
00260     g_UserGenerator.GetSkeletonCap().RequestCalibration(nId, TRUE);
00261   }
00262 
00263 void XN_CALLBACK_TYPE User_LostUser(xn::UserGenerator& generator, XnUserID nId, void* pCookie)
00264   {
00265     printf("Lost user %d\n", nId);
00266   }
00267 
00268 void XN_CALLBACK_TYPE UserCalibration_CalibrationStart(xn::SkeletonCapability& capability, XnUserID nId, void* pCookie)
00269   {
00270     printf("Calibration started for user %d\n", nId);
00271   }
00272 
00273 void XN_CALLBACK_TYPE UserCalibration_CalibrationEnd(xn::SkeletonCapability& capability, XnUserID nId, XnBool bSuccess, void* pCookie)
00274   {
00275     if (bSuccess)
00276       {
00277         printf("Calibration complete, start tracking user %d\n", nId);
00278         g_UserGenerator.GetSkeletonCap().StartTracking(nId);
00279       }
00280     else
00281       {
00282         printf("Calibration failed for user %d\n", nId);
00283         if (g_bNeedPose)
00284         g_UserGenerator.GetPoseDetectionCap().StartPoseDetection(g_strPose, nId);
00285         else
00286         g_UserGenerator.GetSkeletonCap().RequestCalibration(nId, TRUE);
00287       }
00288   }
00289 
00290 void XN_CALLBACK_TYPE UserPose_PoseDetected(xn::PoseDetectionCapability& capability, XnChar const* strPose, XnUserID nId, void* pCookie)
00291   {
00292     printf("Pose %s detected for user %d\n", strPose, nId);
00293     g_UserGenerator.GetPoseDetectionCap().StopPoseDetection(nId);
00294     g_UserGenerator.GetSkeletonCap().RequestCalibration(nId, TRUE);
00295   }
00296 
00297 XnPoint3D
00298 getBodyLoc(XnUserID const& user, XnSkeletonJoint const& eJoint1)
00299 {
00300   XnPoint3D pt;
00301 
00302   // Fault Check
00303   if (!g_UserGenerator.GetSkeletonCap().IsTracking(user))
00304     {
00305       printf("not tracked!\n");
00306       pt.X = 0.0;
00307       pt.Y = 0.0;
00308       pt.Z = 0.0;
00309       return pt;
00310     }
00311 
00312   // Get joint position (this is supposed to be "the Torso point" of the skeleton)
00313   XnSkeletonJointPosition joint1;
00314   g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(user, eJoint1, joint1);
00315 
00316   // Make sure that all joints are found with enough confidence...
00317   if (joint1.fConfidence < 0.7)
00318     {
00319       pt.X = 0.0;
00320       pt.Y = 0.0;
00321       pt.Z = 0.0;
00322       return pt;
00323     }
00324 
00325   pt = joint1.position; // Return the position
00326   return pt;
00327 }
00328 
00329 // Get and return the angle between two NOT JOINT limbs of the skeleton, e.g. angle between (hip to hip vector) ^ ( upper arm )
00330 // !!!!! NOTE : This method originally comes from  the nao teleop stack 
00331 float
00332 getAngleBetweenLimbs(XnUserID const& user, XnSkeletonJoint const& eJoint1,
00333     XnSkeletonJoint const& eJoint2, XnSkeletonJoint const& eJoint3, XnSkeletonJoint const& eJoint4)
00334 {
00335 
00336   // This function is different than getLimbAngle, in the sense that, it finds the angle of two disconnected
00337   // limbs (each limb considered as a vector).
00338 
00339   // In order to find the shoulder roll angleo, we need to find the angle between
00340   // [Right Hip --> Left Hip] vector and [Right Shoulder --> Right Elbow] vector
00341 
00342   if (!g_UserGenerator.GetSkeletonCap().IsTracking(user))
00343     {
00344       printf("not tracked!\n");
00345       return -998.0; // Error code (though, it's not used yet)
00346     }
00347 
00348   // Get joint positions
00349   XnSkeletonJointPosition joint1, joint2, joint3, joint4;
00350   g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(user, eJoint1, joint1);
00351   g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(user, eJoint2, joint2);
00352   g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(user, eJoint3, joint3);
00353   g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(user, eJoint4, joint4);
00354 
00355   // Make sure that all joints are found with enough confidence...
00356   if (joint1.fConfidence < 0.6 && joint2.fConfidence < 0.6 && joint3.fConfidence < 0.6
00357       && joint4.fConfidence < 0.6)
00358     {
00359       return -999.0; // Error code (though, it's not used yet)
00360     }
00361 
00362   XnPoint3D pt[4]; // Create four points
00363   pt[0] = joint1.position; // Vector 0, Point 0
00364   pt[1] = joint2.position; // Vector 0, Point 1
00365   pt[2] = joint3.position; // Vector 1, Point 0
00366   pt[3] = joint4.position; // Vector 1, Point 1
00367 
00368   XnVector3D v[2]; // Create two vectors
00369 
00370   // First vector
00371   // V_{RHIP,LHIP} = V_{LHIP} - V_{RHIP}
00372   v[0].X = pt[2].X - pt[3].X;
00373   v[0].Y = pt[2].Y - pt[3].Y;
00374   v[0].Z = pt[2].Z - pt[3].Z;
00375 
00376   // Second vector
00377   // V_{S,E} = V_{E} - V_{S}
00378   v[1].X = pt[0].X - pt[1].X;
00379   v[1].Y = pt[0].Y - pt[1].Y;
00380   v[1].Z = pt[0].Z - pt[1].Z;
00381 
00382   // Calculate the magnitude of the vectors (limbs)
00383   float v0_magnitude = sqrt(v[0].X * v[0].X + v[0].Y * v[0].Y + v[0].Z * v[0].Z);
00384   float v1_magnitude = sqrt(v[1].X * v[1].X + v[1].Y * v[1].Y + v[1].Z * v[1].Z);
00385 
00386   //printf("V0 MAG: %f, V1 MAG: %f\n",v0_magnitude, v1_magnitude);
00387 
00388   // If neither of vectors != 0.0 then find the angle between them
00389   if (v0_magnitude != 0.0 && v1_magnitude != 0.0)
00390     {
00391       v[0].X = v[0].X * (1.0 / v0_magnitude);
00392       v[0].Y = v[0].Y * (1.0 / v0_magnitude);
00393       v[0].Z = v[0].Z * (1.0 / v0_magnitude);
00394 
00395       v[1].X = v[1].X * (1.0 / v1_magnitude);
00396       v[1].Y = v[1].Y * (1.0 / v1_magnitude);
00397       v[1].Z = v[1].Z * (1.0 / v1_magnitude);
00398 
00399       // Find and convert the angle between upper and lower arms
00400       float theta = acos(v[0].X * v[1].X + v[0].Y * v[1].Y + v[0].Z * v[1].Z);
00401       float angle_in_degrees = theta * 180 / my_pi;
00402 
00403       return angle_in_degrees;
00404     }
00405   else
00406     return -997.0; // Error code (though, it's not used yet)
00407 }
00408 
00409 // Get and return the angle between JOINT limbs (e.g. upper arm ^ lower arm; upper leg ^ lower leg; hip_to_hip ^ upper_leg etc.)
00410 // !!!!! NOTE : This method originally comes from  the nao teleop stack 
00411 float
00412 getLimbAngle(XnUserID const& user, XnSkeletonJoint const& eJoint1, XnSkeletonJoint const& eJoint2,
00413     XnSkeletonJoint const& eJoint3)
00414 {
00415   if (!g_UserGenerator.GetSkeletonCap().IsTracking(user))
00416     {
00417       printf("not tracked!\n");
00418       return -998.0; // Error code (though, it's not used yet)
00419     }
00420 
00421   // Get joint positions
00422   XnSkeletonJointPosition joint1, joint2, joint3;
00423   g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(user, eJoint1, joint1);
00424   g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(user, eJoint2, joint2);
00425   g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(user, eJoint3, joint3);
00426 
00427   // Make sure that all joints are found with enough confidence...
00428   if (joint1.fConfidence < 0.6 && joint2.fConfidence < 0.6 && joint3.fConfidence < 0.6)
00429     {
00430       return -999.0; // Error code (though, it's not used yet)
00431     }
00432 
00433   XnPoint3D pt[3]; // Create 3 points
00434   pt[0] = joint1.position; // E.g. Shoulder
00435   pt[1] = joint2.position; // E.g. Elbow
00436   pt[2] = joint3.position; // E.g. Hand
00437 
00438   XnVector3D v[2]; // Create two vectors
00439 
00440   // S: Shoulder, E: Elbow, H: Hand
00441   // S  *
00442   //    |
00443   // E  *---*
00444   //        H
00445 
00446   // Calculate the first vector
00447   // V_{H,E} = V_{E} - V_{H}
00448   v[0].X = pt[1].X - pt[2].X;
00449   v[0].Y = pt[1].Y - pt[2].Y;
00450   v[0].Z = pt[1].Z - pt[2].Z;
00451 
00452   // Calculate the second vector
00453   // V_{E,S} = V_{S} - V_{E}
00454   v[1].X = pt[0].X - pt[1].X;
00455   v[1].Y = pt[0].Y - pt[1].Y;
00456   v[1].Z = pt[0].Z - pt[1].Z;
00457 
00458   // Calculate the magnitudes of the vectors
00459   float v0_magnitude = sqrt(v[0].X * v[0].X + v[0].Y * v[0].Y + v[0].Z * v[0].Z);
00460   float v1_magnitude = sqrt(v[1].X * v[1].X + v[1].Y * v[1].Y + v[1].Z * v[1].Z);
00461 
00462 
00463   if (v0_magnitude != 0.0 && v1_magnitude != 0.0)
00464     {
00465       v[0].X = v[0].X * (1.0 / v0_magnitude);
00466       v[0].Y = v[0].Y * (1.0 / v0_magnitude);
00467       v[0].Z = v[0].Z * (1.0 / v0_magnitude);
00468 
00469       v[1].X = v[1].X * (1.0 / v1_magnitude);
00470       v[1].Y = v[1].Y * (1.0 / v1_magnitude);
00471       v[1].Z = v[1].Z * (1.0 / v1_magnitude);
00472 
00473       // Find and convert the angle between JOINT limbs
00474       float theta = acos(v[0].X * v[1].X + v[0].Y * v[1].Y + v[0].Z * v[1].Z);
00475       float angle_in_degrees = theta * 180 / my_pi;
00476 
00477       return angle_in_degrees;
00478     }
00479   else
00480     return -997.0; // Error code (though, it's not used yet)
00481 }
00482 
00483 // Gives the angle between:
00484 // the initial AND current position of the user's shoulders, to understand how much he/she rotated his/her shoulders.
00485 float
00486 getTorsoRotation(XnUserID const& user, XnSkeletonJoint const& eJoint1,
00487     XnSkeletonJoint const& eJoint2)
00488 {
00489 
00490   if (!g_UserGenerator.GetSkeletonCap().IsTracking(user))
00491     {
00492       printf("not tracked!\n");
00493       return -998.0; // Error code (though, it's not used yet)
00494     }
00495 
00496   // Get joint positions
00497   XnSkeletonJointPosition joint1, joint2;
00498   g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(user, eJoint1, joint1);
00499   g_UserGenerator.GetSkeletonCap().GetSkeletonJointPosition(user, eJoint2, joint2);
00500 
00501   // Make sure that all joints are found with enough confidence...
00502   if (joint1.fConfidence < 0.6 && joint2.fConfidence < 0.6)
00503     {
00504       return -999.0; // Error code (though, it's not used yet)
00505     }
00506 
00507   XnPoint3D pt[4]; // Create four points
00508   pt[0] = init_usr_LS; // Vector 0, Point 0 - Initial location of the left shoulder
00509   pt[1] = init_usr_RS; // Vector 0, Point 1 - Initial location of the right shoulder
00510   pt[2] = joint1.position; // Vector 1, Point 0 - Current location of the left shoulder
00511   pt[3] = joint2.position; // Vector 1, Point 1 - Current location of the right shoulder
00512 
00513   XnVector3D v[2]; // Create two vectors
00514 
00515   // Assign the vectors
00516   v[0].X = pt[2].X - pt[3].X;
00517   v[0].Y = pt[2].Y - pt[3].Y;
00518   v[0].Z = pt[2].Z - pt[3].Z;
00519 
00520   v[1].X = pt[0].X - pt[1].X;
00521   v[1].Y = pt[0].Y - pt[1].Y;
00522   v[1].Z = pt[0].Z - pt[1].Z;
00523 
00524   // Calculate the magnitude of the vectors
00525   float v0_magnitude = sqrt(v[0].X * v[0].X + v[0].Y * v[0].Y + v[0].Z * v[0].Z);
00526   float v1_magnitude = sqrt(v[1].X * v[1].X + v[1].Y * v[1].Y + v[1].Z * v[1].Z);
00527 
00528   //printf("V0 MAG: %f, V1 MAG: %f\n",v0_magnitude, v1_magnitude);
00529 
00530   // If neither of the vectors are != 0.0 then calculate the angle between them
00531   if (v0_magnitude != 0.0 && v1_magnitude != 0.0)
00532     {
00533       v[0].X = v[0].X * (1.0 / v0_magnitude);
00534       v[0].Y = v[0].Y * (1.0 / v0_magnitude);
00535       v[0].Z = v[0].Z * (1.0 / v0_magnitude);
00536 
00537       v[1].X = v[1].X * (1.0 / v1_magnitude);
00538       v[1].Y = v[1].Y * (1.0 / v1_magnitude);
00539       v[1].Z = v[1].Z * (1.0 / v1_magnitude);
00540 
00541       // Calculate and convert the angle between the initial and current locations of the shoulders
00542       float theta = acos(v[0].X * v[1].X + v[0].Y * v[1].Y + v[0].Z * v[1].Z);
00543       float angle_in_degrees = theta * 180 / my_pi;
00544 
00545       return angle_in_degrees;
00546     }
00547   else
00548     return -997.0; // Error code (though, it's not used yet)
00549 }
00550 
00551 void
00552 checkPose(TeleopPR2Ni &obj)
00553 {
00554   XnUserID users[2];
00555   XnUInt16 users_count = 2;
00556   g_UserGenerator.GetUsers(users, users_count);
00557   obj.teleopEnabled_ = false;
00558 
00559   for (int i = 0; i < users_count; ++i)
00560     {
00561       XnUserID user = users[i];
00562       if (!g_UserGenerator.GetSkeletonCap().IsTracking(user))
00563         continue;
00564 
00565       obj.teleopEnabled_ = true;
00566       /*  If right and left shoulder - elbow - hand make 90 (+/-5) degrees
00567        *  with a certain confidence switch to teleoperation mode
00568        */
00569 
00570       // Get the current body (torso) location
00571       XnPoint3D current_bl = getBodyLoc(user, XN_SKEL_TORSO);
00572 
00573       // Get the current right shoulder locations
00574       XnPoint3D current_rs = getBodyLoc(user, XN_SKEL_RIGHT_SHOULDER);
00575       // Get the current left shoulder locations
00576       XnPoint3D current_ls = getBodyLoc(user, XN_SKEL_LEFT_SHOULDER);
00577 
00578       // if positive rotate right, else rotate left
00579       //      float current_angle = getTorsoRotation(user, XN_SKEL_LEFT_SHOULDER, XN_SKEL_RIGHT_SHOULDER)
00580       //          * my_pi / 180.0;
00581 
00582       // Right shoulder angles pitch
00583       float rsap = getLimbAngle(user, XN_SKEL_RIGHT_HIP, XN_SKEL_RIGHT_SHOULDER,
00584           XN_SKEL_RIGHT_ELBOW) * my_pi / 180.0;
00585       rsap = rsap - 1.6;
00586       if (rsap >= -0.5 && rsap <= 1.4)
00587         {
00588           obj.rShoulderAngles_.pitch = rsap;
00589         }
00590       //      printf("Right Shoulder Pitch: %f\n", rsap);
00591 
00592       // Right elbow angle roll
00593       float rear = getLimbAngle(user, XN_SKEL_RIGHT_SHOULDER, XN_SKEL_RIGHT_ELBOW,
00594           XN_SKEL_RIGHT_HAND) * my_pi / 180.0;
00595       if (2.4 >= rear && rear >= 0.0)
00596         {
00597           obj.rElbowAngles_.pitch = rear;
00598         }
00599       //printf("Right elbow Pitch: %f\n", rear);
00600 
00601       // Right elbow angle yaw
00602       float reay = getAngleBetweenLimbs(user, XN_SKEL_RIGHT_SHOULDER, XN_SKEL_RIGHT_HIP,
00603           XN_SKEL_RIGHT_ELBOW, XN_SKEL_RIGHT_HAND) * my_pi / 180.0;
00604       reay = reay - 2.8; //1.57;
00605       if (0.8 >= reay && reay >= -3.9)
00606         {
00607           obj.rElbowAngles_.yaw = reay;
00608         }
00609       //printf("Right elbow yaw: %f\n", reay);
00610 
00611       // Right shoulder angle roll
00612       float rsar = getAngleBetweenLimbs(user, XN_SKEL_RIGHT_HIP, XN_SKEL_LEFT_HIP,
00613           XN_SKEL_RIGHT_SHOULDER, XN_SKEL_RIGHT_ELBOW) * my_pi / 180.0;
00614       // In front: 90 (1.57) --> -0.5
00615       // Wide open: 180 (3.14) --> -94.5
00616 
00617       rsar = 1.63 - rsar;
00618       if ( 0.7 >= rsar && rsar >= -2.3)
00619         {
00620           obj.rShoulderAngles_.yaw = rsar;
00621         }
00622 
00623       // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00624       // NOW the same stuff as above for the left shoulder!
00625       // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00626 
00627       // Left shoulder angles pitch
00628       float lsap = getLimbAngle(user, XN_SKEL_LEFT_HIP, XN_SKEL_LEFT_SHOULDER, XN_SKEL_LEFT_ELBOW)
00629           * my_pi / 180.0;
00630       lsap = lsap - 1.6;
00631       if (lsap >= -0.5 && lsap <= 1.4)
00632         {
00633           obj.lShoulderAngles_.pitch = lsap;
00634         }
00635       //      printf("Left Shoulder Pitch: %f\n", rsap);
00636 
00637       // Left elbow angle roll
00638       float lear = getLimbAngle(user, XN_SKEL_LEFT_SHOULDER, XN_SKEL_LEFT_ELBOW, XN_SKEL_LEFT_HAND)
00639           * my_pi / 180.0;
00640       if (2.4 >= lear && lear >= 0.0)
00641         {
00642           obj.lElbowAngles_.pitch = lear;
00643         }
00644       //printf("Left elbow Pitch: %f\n", rear);
00645 
00646       // Left elbow angle yaw
00647       float leay = getAngleBetweenLimbs(user, XN_SKEL_LEFT_SHOULDER, XN_SKEL_LEFT_HIP,
00648           XN_SKEL_LEFT_ELBOW, XN_SKEL_LEFT_HAND) * my_pi / 180.0;
00649       leay = 2.8 - leay; //1.57;
00650       if (3.9 >= leay && leay >= -0.8)
00651         {
00652           obj.lElbowAngles_.yaw = leay;
00653         }
00654       //printf("Left elbow yaw: %f\n", reay);
00655 
00656       // Left shoulder angle roll
00657       float lsar = getAngleBetweenLimbs(user, XN_SKEL_LEFT_HIP, XN_SKEL_RIGHT_HIP,
00658           XN_SKEL_LEFT_SHOULDER, XN_SKEL_LEFT_ELBOW) * my_pi / 180.0;
00659       // In front: 90 (1.57) --> -0.5
00660       // Wide open: 180 (3.14) --> -94.5
00661 
00662       lsar = lsar - 1.63;
00663       if (2.3 >= lsar && lsar >= -0.7)
00664         {
00665           //lsar = -1. *lsar;
00666           obj.lShoulderAngles_.yaw = lsar;
00667         }
00668       //ROS_INFO("lsar %f rsar %f", lsar, rsar );
00669     }
00670 }
00671 
00672 int
00673 main(int argc, char** argv)
00674 {
00675 
00676   ros::init(argc, argv, "teleop_pr2_ni");// Initialize ROS
00677 
00678   bool useLeftArm = true;
00679   arm_client_r = new TrajClient("r_arm_controller/joint_trajectory_action", true);
00680   arm_client_l = new TrajClient("l_arm_controller/joint_trajectory_action", true);
00681 
00682   ros::NodeHandle n("/kinect_teleop");
00683 
00684   // check if left arm should be used as well
00685   if (!n.getParam("use_left_arm", useLeftArm))
00686     {
00687       ROS_INFO("Not using left arm!");
00688       useLeftArm = false;
00689     }
00690 
00691   //wait for the action server to come up
00692   while (!arm_client_r->waitForServer(ros::Duration(5.0)))
00693     {
00694       ROS_INFO("Waiting for the right arm action server to come up");
00695     }
00696   while (useLeftArm && !arm_client_l->waitForServer(ros::Duration(5.0)))
00697     {
00698       ROS_INFO("Waiting for the left arm action server to come up");
00699     }
00700 
00701   TeleopPR2Ni teleopPR2;// Declare and initialize the variables and object(s)
00702   teleopPR2.useLeftArm_ = useLeftArm;
00703   string configFilename = ros::package::getPath("kinect_teleop") + "/openni_tracker.xml";
00704 
00705   int count = 0;
00706   double publishRate = 50; 
00707   teleopPR2.privateNh_.param("motion_publish_rate", publishRate, publishRate);
00708   ros::Rate pubRate(publishRate); // Set the publishing rate
00709 
00710   // OpenNI functions begin -------------------------------------------------
00711   // Refer to OpenNI Manual and Discussion Group to get help about these functions and variables
00712   XnStatus nRetVal = g_Context.InitFromXmlFile(configFilename.c_str());
00713   CHECK_RC(nRetVal, "InitFromXml");
00714 
00715   nRetVal = g_Context.FindExistingNode(XN_NODE_TYPE_DEPTH, g_DepthGenerator);
00716   CHECK_RC(nRetVal, "Find depth generator");
00717 
00718   nRetVal = g_Context.FindExistingNode(XN_NODE_TYPE_USER, g_UserGenerator);
00719   if (nRetVal != XN_STATUS_OK)
00720     {
00721       nRetVal = g_UserGenerator.Create(g_Context);
00722       CHECK_RC(nRetVal, "Find user generator");
00723     }
00724 
00725   if (!g_UserGenerator.IsCapabilitySupported(XN_CAPABILITY_SKELETON))
00726     {
00727       printf("Supplied user generator doesn't support skeleton\n");
00728       return 1;
00729     }
00730 
00731   XnCallbackHandle hUserCallbacks;
00732   g_UserGenerator.RegisterUserCallbacks(User_NewUser, User_LostUser, NULL, hUserCallbacks);
00733 
00734   XnCallbackHandle hCalibrationCallbacks;
00735   g_UserGenerator.GetSkeletonCap().RegisterCalibrationCallbacks(UserCalibration_CalibrationStart,
00736       UserCalibration_CalibrationEnd, NULL, hCalibrationCallbacks);
00737 
00738   if (g_UserGenerator.GetSkeletonCap().NeedPoseForCalibration())
00739     {
00740       g_bNeedPose = TRUE;
00741       if (!g_UserGenerator.IsCapabilitySupported(XN_CAPABILITY_POSE_DETECTION))
00742         {
00743           printf("Pose required, but not supported\n");
00744           return 1;
00745         }
00746 
00747       XnCallbackHandle hPoseCallbacks;
00748       g_UserGenerator.GetPoseDetectionCap().RegisterToPoseCallbacks(UserPose_PoseDetected, NULL,
00749           NULL, hPoseCallbacks);
00750 
00751       g_UserGenerator.GetSkeletonCap().GetCalibrationPose(g_strPose);
00752     }
00753 
00754   g_UserGenerator.GetSkeletonCap().SetSkeletonProfile(XN_SKEL_PROFILE_ALL);
00755 
00756   nRetVal = g_Context.StartGeneratingAll();
00757   CHECK_RC(nRetVal, "StartGenerating");
00758   // OpenNI functions end-------------------------------------------------
00759 
00760   // Endless loop to publish messages
00761   while (teleopPR2.nh_.ok())
00762     {
00763 
00764       g_Context.WaitAndUpdateAll(); // Update skeleton recognition (OpenNI's callbacks)
00765 
00766       checkPose(teleopPR2); // Check user's pose and assign according values to the messages that will be published
00767 
00768       teleopPR2.updateTrajectory(publishRate); // Update Trajectory
00769 
00770       if (count % 3 == 0)
00771         {
00772           teleopPR2.pubMsg(publishRate / 50); // Publish messages to PR2
00773           count = 0;
00774         }
00775 
00776       ++count;
00777       pubRate.sleep(); // Sleep to get to the rate of publishing
00778     }
00779 
00780   g_Context.Shutdown(); // Close OpenNI
00781   return 0;
00782 
00783 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


kinect_teleop
Author(s): Jan Wülfing
autogenerated on Wed Dec 26 2012 16:45:13