lmc_listener.cpp
Go to the documentation of this file.
1 #include "ros/ros.h"
5 
6 #include "leap_motion/Human.h"
7 #include "leap_motion/Hand.h"
8 #include "leap_motion/Finger.h"
9 #include "leap_motion/Bone.h"
10 #include "leap_motion/Gesture.h"
11 
12 #include <iostream>
13 
14 #include "../inc/lmc_listener.h"
15 #include "Leap.h"
16 
17 using namespace Leap;
18 
19 const std::string fingerNames[] = {"Thumb", "Index", "Middle", "Ring", "Pinky"};
20 
29  header_frame_id_ = "leap_hands";
30 
31  enable_controller_info_ = false;
32  enable_frame_info_ = false;
33  enable_hand_info_ = false;
34 
35  enable_gesture_circle_ = false;
36  enable_gesture_swipe_ = false;
37  enable_gesture_screen_tap_ = false;
38  enable_gesture_key_tap_ = false;
39 }
40 
50  header_frame_id_ = "leap_hands";
51 
52  enable_controller_info_ = args[0];
53  enable_frame_info_ = args[1];
54  enable_hand_info_ = args[2];
55 
56  enable_gesture_circle_ = args[3];
57  enable_gesture_swipe_ = args[4];
58  enable_gesture_screen_tap_ = args[5];
59  enable_gesture_key_tap_ = args[6];
60 }
61 
70 void LeapListener::onConnect(const Controller& controller)
71 {
73  {
74  const DeviceList devices = controller.devices();
75  for (int i = 0; i < devices.count(); ++i)
76  {
77  ROS_INFO( "id: %s", devices[i].toString().c_str() );
78  ROS_INFO(" isStreaming: %s", (devices[i].isStreaming() ? "true" : "false") );
79  }
80  }
81 
82  // A circular movement by a finger.
84  {
87  {
88  ROS_INFO("Circle gesture has been enabled");
89  }
90  }
91 
92  // A straight line movement by the hand with fingers extended.
94  {
97  {
98  ROS_INFO("Swipe gesture has been enabled");
99  }
100  }
101 
102  // A forward tapping movement by a finger.
104  {
107  {
108  ROS_INFO("Screen tap gesture has been enabled");
109  }
110  }
111 
112  // A downward tapping movement by a finger.
114  {
117  {
118  ROS_INFO("Key tap gesture has been enabled");
119  }
120  }
121 };
122 
131 void LeapListener::onInit(const Controller& controller)
132 {
134  {
135  ROS_INFO("Listener has been initialized");
136  }
137 };
138 
151 void LeapListener::onDisconnect(const Controller& controller)
152 {
154  {
155  ROS_INFO("Device disconnected");
156  }
157 };
158 
167 void LeapListener::onExit(const Controller& controller)
168 {
170  {
171  ROS_INFO("Listener object removed from the device");
172  }
173 };
174 
189 void LeapListener::onFrame(const Controller& controller)
190 {
191  const Frame frame = controller.frame();
192  ros::Time timestamp = ros::Time::now();
193 
194  // Create an instance of leap_motion::human message
195  // and fill it with all the possible data from the Leap Motion controller
196  leap_motion::Human ros_human_msg;
197  ros_human_msg.header.stamp = timestamp;
198  ros_human_msg.header.frame_id = LeapListener::header_frame_id_;
199  ros_human_msg.lmc_frame_id = frame.id();
200  ros_human_msg.nr_of_hands = frame.hands().count();
201  ros_human_msg.nr_of_fingers = frame.fingers().count();
202  ros_human_msg.nr_of_gestures = frame.gestures().count();
203  ros_human_msg.current_frames_per_second = frame.currentFramesPerSecond();
204  ros_human_msg.to_string = frame.toString();
205 
206  ros_human_msg.right_hand.is_present = false;
207  ros_human_msg.left_hand.is_present = false;
208 
210  {
211  ROS_INFO("Frame id: %lu, timestamp: %f, hands: %i, fingers: %i, gestures: %i",
212  frame.id(), timestamp.toSec(), frame.hands().count(), frame.fingers().count(),
213  frame.gestures().count() );
214  }
215 
216  // Get a list of all of the hands detected in the frame
217  HandList hand_list = frame.hands();
218  if(hand_list.count() > 2)
219  {
220  ROS_WARN("There are more than 2 hands in the frame! I see %i hands.", hand_list.count());
221  }
222  else
223  {
224  for (HandList::const_iterator current_hand = hand_list.begin(); current_hand != hand_list.end(); ++current_hand)
225  {
226  // Get a hand from the list
227  const Hand hand = *current_hand;
228 
229  // Create an instance of leap_motion::Hand message
230  // and fill it with all the possible data from the Leap::Hand object
231  leap_motion::Hand ros_hand_msg;
232  ros_hand_msg.header.stamp = timestamp;
233  ros_hand_msg.header.frame_id = LeapListener::header_frame_id_;
234  ros_hand_msg.lmc_hand_id = hand.id();
235  ros_hand_msg.is_present = true; // Override the default value
236  ros_hand_msg.valid_gestures = false; // No gestures associated with this hand
237  ros_hand_msg.confidence = hand.confidence(); // How confident the controller is with a given hand pose between [0,1] inclusive.
238 
239  // Get hand's roll-pitch-yaw as defined by leap
240  ros_hand_msg.roll = hand.palmNormal().roll(); // The roll angle in radians.
241  ros_hand_msg.pitch = hand.direction().pitch(); // The pitch angle in radians.
242  ros_hand_msg.yaw = hand.direction().yaw(); // The yaw angle in radians.
243 
244  // Get hand's direction vector
245  ros_hand_msg.direction.x = hand.direction().x;
246  ros_hand_msg.direction.y = hand.direction().y;
247  ros_hand_msg.direction.z = hand.direction().z;
248 
249  // Get hand's normal vector
250  ros_hand_msg.normal.x = hand.palmNormal().x;
251  ros_hand_msg.normal.y = hand.palmNormal().y;
252  ros_hand_msg.normal.z = hand.palmNormal().z;
253 
254  ros_hand_msg.grab_strength = hand.grabStrength(); // The angle between the fingers and the hand of a grab hand pose.
255  ros_hand_msg.palm_width = hand.palmWidth() / 1000.0; // in m
256  ros_hand_msg.pinch_strength = hand.pinchStrength(); // The distance between the thumb and index finger of a pinch hand pose.
257  ros_hand_msg.time_visible = hand.timeVisible(); // The duration (in seconds) that this Hand has been tracked.
258  ros_hand_msg.to_string = hand.toString();
259 
260  // The rate of change of the palm position (x,y,z) in m/s.
261  ros_hand_msg.palm_velocity.push_back(hand.palmVelocity()[0] / 1000.0);
262  ros_hand_msg.palm_velocity.push_back(hand.palmVelocity()[1] / 1000.0);
263  ros_hand_msg.palm_velocity.push_back(hand.palmVelocity()[2] / 1000.0);
264 
265  // The center of a sphere fit to the curvature of this hand in m.
266  ros_hand_msg.sphere_center.push_back(hand.sphereCenter()[0] / 1000.0);
267  ros_hand_msg.sphere_center.push_back(hand.sphereCenter()[1] / 1000.0);
268  ros_hand_msg.sphere_center.push_back(hand.sphereCenter()[2] / 1000.0);
269 
270  ros_hand_msg.sphere_radius = hand.sphereRadius() / 1000.0; // in m
271 
273  {
274  ROS_INFO("%s %s, id: %i, palm position: %s mm", std::string(2, ' ').c_str(),
275  (hand.isRight() ? "Right hand" : "Left hand"), hand.id(), hand.palmPosition().toString().c_str() );
276  }
277 
278  // The center position of the palm in meters from the Leap Motion Controller origin.
279  ros_hand_msg.palm_center.x = hand.palmPosition().x / 1000.0;
280  ros_hand_msg.palm_center.y = hand.palmPosition().y / 1000.0;
281  ros_hand_msg.palm_center.z = hand.palmPosition().z / 1000.0;
282 
283  // If this is a left hand, we need to convert rotation matrices to right-handed by negating the x basis
284  float x_basis_sign = 1.0;
285  if (!hand.isRight())
286  {
287  x_basis_sign = -1.0;
288  }
289 
290  // This is a list of finger messages that will be attached to the hand message
291  std::vector<leap_motion::Finger> finger_msg_list;
292 
293  // Given in order from thumb[idx 0] to pinky[idx 4].
294  const FingerList fingers = hand.fingers();
295  for (FingerList::const_iterator fl = fingers.begin(); fl != fingers.end(); ++fl)
296  {
297  // Get a finger from the list
298  const Finger finger = *fl;
299 
300  leap_motion::Finger ros_finger_msg;
301  ros_finger_msg.header.stamp = timestamp;
302  ros_finger_msg.header.frame_id = LeapListener::header_frame_id_;
303  ros_finger_msg.lmc_finger_id = finger.id();
304  ros_finger_msg.type = finger.type();
305  ros_finger_msg.length = finger.length() / 1000.0;
306  ros_finger_msg.width = finger.width() / 1000.0;
307  ros_finger_msg.to_string = finger.toString();
308 
310  {
311  ROS_INFO("%s %s, id: %i, length: %f mm, width: %f mm", std::string(4, ' ').c_str(),
312  fingerNames[finger.type()].c_str(), finger.id(), finger.length(), finger.width());
313  }
314 
315  Bone bone;
316  Bone::Type boneType;
317  std::vector<leap_motion::Bone> bone_msg_list;
318  for (int b = 0; b < 4; ++b)
319  {
320  // Get current fingers bone at index b
321  boneType = static_cast<Bone::Type>(b);
322  bone = finger.bone(boneType);
323 
324  leap_motion::Bone ros_bone_msg;
325  ros_bone_msg.type = boneType;
326  ros_bone_msg.length = bone.length() / 1000.0; // in m
327  ros_bone_msg.width = bone.width() / 1000.0; // in m
328  ros_bone_msg.to_string = bone.toString(); // human readable description of the Bone object
329 
330  ros_bone_msg.center.push_back(bone.center()[0] / 1000.0); // x in m
331  ros_bone_msg.center.push_back(bone.center()[1] / 1000.0); // y in m
332  ros_bone_msg.center.push_back(bone.center()[2] / 1000.0); // z in m
333 
334  ros_bone_msg.bone_start.position.x = bone.prevJoint().x / 1000.0;
335  ros_bone_msg.bone_start.position.y = bone.prevJoint().y / 1000.0;
336  ros_bone_msg.bone_start.position.z = bone.prevJoint().z / 1000.0;
337 
338  ros_bone_msg.bone_end.position.x = bone.nextJoint().x / 1000.0;
339  ros_bone_msg.bone_end.position.y = bone.nextJoint().y / 1000.0;
340  ros_bone_msg.bone_end.position.z = bone.nextJoint().z / 1000.0;
341 
342  // Get bone rotation using basis vectors and store it in bone_start and bone_end Poses.
343  Leap::Matrix leap_matrix = bone.basis();
344  tf::Matrix3x3 tf_matrix(x_basis_sign * leap_matrix.xBasis.x, x_basis_sign * leap_matrix.xBasis.y,
345  x_basis_sign * leap_matrix.xBasis.z,
346  leap_matrix.yBasis.x, leap_matrix.yBasis.y, leap_matrix.yBasis.z,
347  leap_matrix.zBasis.x, leap_matrix.zBasis.y, leap_matrix.zBasis.z);
348  tf::Quaternion tf_quaternion;
349  tf_matrix.getRotation(tf_quaternion);
350  quaternionTFToMsg(tf_quaternion, ros_bone_msg.bone_end.orientation);
351  ros_bone_msg.bone_start.orientation = ros_bone_msg.bone_end.orientation;
352  bone_msg_list.push_back(ros_bone_msg);
353  }
354 
355  ros_finger_msg.bone_list = bone_msg_list;
356  finger_msg_list.push_back(ros_finger_msg);
357  }
358 
359  ros_hand_msg.finger_list = finger_msg_list;
360 
361  // Check if there are any gestures associated wih this frame
362  // if there are, connect them with the correct hand
363  if (!frame.gestures().isEmpty())
364  {
365  std::vector<leap_motion::Gesture> gesture_msg_list;
366  ros_hand_msg.valid_gestures = true;
367 
368  Leap::GestureList gestures = frame.gestures();
369  for(Leap::GestureList::const_iterator gl = gestures.begin(); gl != gestures.end(); gl++)
370  {
371  // Check what hands are connected with a particular gesture
372  Leap::HandList hands_for_gesture = (*gl).hands();
373  for(unsigned int i = 0; i < hands_for_gesture.count(); i++)
374  {
375  if(*current_hand == hands_for_gesture[i])
376  {
377  leap_motion::Gesture ros_gesture_msg;
378  ros_gesture_msg.lmc_gesture_id = (*gl).id();
379  ros_gesture_msg.duration_us = (*gl).duration();
380  ros_gesture_msg.duration_s = (*gl).durationSeconds();
381  ros_gesture_msg.is_valid = (*gl).isValid();
382  ros_gesture_msg.gesture_state = (*gl).state();
383  ros_gesture_msg.gesture_type = (*gl).type();
384  ros_gesture_msg.to_string = (*gl).toString();
385 
386  // Appends the ids of pointable objects related with this gesture
387  Leap::PointableList pointables_for_gesture = (*gl).pointables();
388  std::vector<int32_t> pointable_ids;
389  for(unsigned int j = 0; j < pointables_for_gesture.count(); j++)
390  {
391  pointable_ids.push_back( pointables_for_gesture[j].id() );
392  }
393 
394  ros_gesture_msg.pointable_ids = pointable_ids;
395  gesture_msg_list.push_back(ros_gesture_msg);
396  }
397  }
398  }
399  ros_hand_msg.gesture_list = gesture_msg_list;
400  }
401 
402  // Populate arm details of hand
403  ros_hand_msg.arm.header.stamp = timestamp;
404 
405  ros_hand_msg.arm.elbow.position.x = hand.arm().elbowPosition()[0] / 1000.0;
406  ros_hand_msg.arm.elbow.position.y = hand.arm().elbowPosition()[1] / 1000.0;
407  ros_hand_msg.arm.elbow.position.z = hand.arm().elbowPosition()[2] / 1000.0;
408 
409  ros_hand_msg.arm.center.push_back(hand.arm().center()[0] / 1000.0);
410  ros_hand_msg.arm.center.push_back(hand.arm().center()[1] / 1000.0);
411  ros_hand_msg.arm.center.push_back(hand.arm().center()[2] / 1000.0);
412 
413  ros_hand_msg.arm.wrist.position.x = hand.arm().wristPosition()[0] / 1000.0;
414  ros_hand_msg.arm.wrist.position.y = hand.arm().wristPosition()[1] / 1000.0;
415  ros_hand_msg.arm.wrist.position.z = hand.arm().wristPosition()[2] / 1000.0;
416 
417  ros_hand_msg.arm.direction.x = hand.arm().center()[0] / 1000.0;
418  ros_hand_msg.arm.direction.y = hand.arm().center()[1] / 1000.0;
419  ros_hand_msg.arm.direction.z = hand.arm().center()[2] / 1000.0;
420 
421  // Get arm rotation using basis vectors and store it in bone_start and bone_end Poses.
422  Leap::Matrix leap_matrix = hand.arm().basis();
423  tf::Matrix3x3 tf_matrix(x_basis_sign * leap_matrix.xBasis.x, x_basis_sign * leap_matrix.xBasis.y,
424  x_basis_sign * leap_matrix.xBasis.z,
425  leap_matrix.yBasis.x, leap_matrix.yBasis.y, leap_matrix.yBasis.z,
426  leap_matrix.zBasis.x, leap_matrix.zBasis.y, leap_matrix.zBasis.z);
427  tf::Quaternion tf_quaternion;
428  tf_matrix.getRotation(tf_quaternion);
429  quaternionTFToMsg(tf_quaternion, ros_hand_msg.arm.elbow.orientation);
430  ros_hand_msg.arm.wrist.orientation = ros_hand_msg.arm.elbow.orientation;
431 
432  if( hand.isRight() )
433  {
434  ros_human_msg.right_hand = ros_hand_msg;
435  }
436  else
437  {
438  ros_human_msg.left_hand = ros_hand_msg;
439  }
440  }
441  ros_publisher.publish(ros_human_msg);
442  }
443 };
Vector xBasis
Definition: LeapMath.h:1021
LEAP_EXPORT void enableGesture(Gesture::Type type, bool enable=true) const
LEAP_EXPORT const_iterator begin() const
LEAP_EXPORT bool isRight() const
bool enable_gesture_swipe_
Definition: lmc_listener.h:34
LEAP_EXPORT float grabStrength() const
LEAP_EXPORT Vector sphereCenter() const
LEAP_EXPORT Vector palmNormal() const
direction
Definition: Leap.py:790
LEAP_EXPORT GestureList gestures() const
bool enable_gesture_screen_tap_
Definition: lmc_listener.h:35
LEAP_EXPORT float pinchStrength() const
#define ROS_WARN(...)
LEAP_EXPORT float currentFramesPerSecond() const
std::string toString() const
Definition: Leap.h:5253
void getRotation(Quaternion &q) const
LEAP_EXPORT int count() const
virtual void onInit(const Controller &)
Called once, when this Listener object is newly added to a Controller.
Definition: Leap.h:48
bool enable_frame_info_
Definition: lmc_listener.h:30
virtual void onFrame(const Controller &)
Called when a new frame of hand and finger tracking data is available.
std::string toString() const
Definition: Leap.h:1728
LEAP_EXPORT Vector palmPosition() const
LEAP_EXPORT float palmWidth() const
LEAP_EXPORT Bone bone(Bone::Type boneIx) const
#define ROS_INFO(...)
Vector yBasis
Definition: LeapMath.h:1029
bool enable_hand_info_
Definition: lmc_listener.h:31
LEAP_EXPORT Vector palmVelocity() const
LeapListener()
Uses default values for initial setup.
LEAP_EXPORT const_iterator end() const
std::string toString() const
Definition: Leap.h:991
bool enable_gesture_circle_
Definition: lmc_listener.h:33
confidence
Definition: Leap.py:823
Vector zBasis
Definition: LeapMath.h:1037
std::string header_frame_id_
Definition: lmc_listener.h:27
virtual void onDisconnect(const Controller &)
Called when the Controller object disconnects.
bool enable_controller_info_
Definition: lmc_listener.h:29
virtual void onExit(const Controller &)
Called when this Listener object is removed from the Controller.
LEAP_EXPORT int count() const
std::string toString() const
Definition: LeapMath.h:499
LEAP_EXPORT int count() const
static Time now()
virtual void onConnect(const Controller &)
Called when a connection is established with the controller.
const std::string fingerNames[]
LEAP_EXPORT float timeVisible() const
LEAP_EXPORT Frame frame(int history=0) const
LEAP_EXPORT const_iterator end() const
LEAP_EXPORT float sphereRadius() const
bool enable_gesture_key_tap_
Definition: lmc_listener.h:36
LEAP_EXPORT bool isEmpty() const
LEAP_EXPORT int count() const
LEAP_EXPORT const_iterator begin() const


leap_motion
Author(s): Florian Lier , Mirza Shah , Isaac IY Saito
autogenerated on Tue Jun 2 2020 03:58:01