tf.cpp
Go to the documentation of this file.
1 // This file implements Astra Body -> ROS tf2 conversion
2 
3 #include "tf.hpp"
4 #include "math.hpp"
5 
6 #include <eigen3/Eigen/Dense>
7 
8 #include <unordered_map>
9 #include <unordered_set>
10 #include <deque>
11 
12 #include <tf2/buffer_core.h>
13 
14 using namespace astra_ros;
15 
16 namespace
17 {
18  // Derived from the graphic on https://shop.orbbec3d.com/Orbbec-Body-Tracking-License_p_55.html
19  // A mapping of frames (parent -> children)
20  const static std::unordered_map<std::uint8_t, std::unordered_set<std::uint8_t>> TF_LINKS {
21  // Torso (BASE_SPINE is the root)
22  {
23  Joint::TYPE_BASE_SPINE, {
24  Joint::TYPE_LEFT_HIP,
25  Joint::TYPE_RIGHT_HIP,
26  Joint::TYPE_MID_SPINE
27  }
28  },
29  { Joint::TYPE_MID_SPINE, { Joint::TYPE_SHOULDER_SPINE } },
30  {
31  Joint::TYPE_SHOULDER_SPINE, {
32  Joint::TYPE_HEAD,
33  Joint::TYPE_RIGHT_SHOULDER,
34  Joint::TYPE_LEFT_SHOULDER
35  }
36  },
37  // Left Arm
38  { Joint::TYPE_LEFT_SHOULDER, { Joint::TYPE_LEFT_ELBOW } },
39  { Joint::TYPE_LEFT_ELBOW, { Joint::TYPE_LEFT_WRIST } },
40  { Joint::TYPE_LEFT_WRIST, { Joint::TYPE_LEFT_HAND } },
41  // Right Arm
42  { Joint::TYPE_RIGHT_SHOULDER, { Joint::TYPE_RIGHT_ELBOW } },
43  { Joint::TYPE_RIGHT_ELBOW, { Joint::TYPE_RIGHT_WRIST } },
44  { Joint::TYPE_RIGHT_WRIST, { Joint::TYPE_RIGHT_HAND } },
45  // Left Leg
46  { Joint::TYPE_LEFT_HIP, { Joint::TYPE_LEFT_FOOT } },
47  { Joint::TYPE_LEFT_KNEE, { Joint::TYPE_LEFT_FOOT } },
48  // Right Leg
49  { Joint::TYPE_RIGHT_HIP, { Joint::TYPE_RIGHT_KNEE } },
50  { Joint::TYPE_RIGHT_KNEE, { Joint::TYPE_RIGHT_FOOT } }
51  };
52 
53  const static std::unordered_map<std::uint8_t, std::string> TF_FRAME_NAMES {
54  // Head
55  { Joint::TYPE_NECK, "neck" },
56  { Joint::TYPE_HEAD, "head" },
57  // Torso
58  { Joint::TYPE_BASE_SPINE, "base_spine" },
59  { Joint::TYPE_MID_SPINE, "mid_spine" },
60  { Joint::TYPE_SHOULDER_SPINE, "shoulder_spine" },
61  // Left Arm
62  { Joint::TYPE_LEFT_SHOULDER, "left_shoulder" },
63  { Joint::TYPE_LEFT_ELBOW, "left_elbow" },
64  { Joint::TYPE_LEFT_WRIST, "left_wrist" },
65  { Joint::TYPE_LEFT_HAND, "left_hand" },
66  // Right Arm
67  { Joint::TYPE_RIGHT_SHOULDER, "right_shoulder" },
68  { Joint::TYPE_RIGHT_ELBOW, "right_elbow" },
69  { Joint::TYPE_RIGHT_WRIST, "right_wrist" },
70  { Joint::TYPE_RIGHT_HAND, "right_hand" },
71  // Left Leg
72  { Joint::TYPE_LEFT_HIP, "left_hip" },
73  { Joint::TYPE_LEFT_KNEE, "left_knee" },
74  { Joint::TYPE_LEFT_FOOT, "left_foot" },
75  // Right Leg
76  { Joint::TYPE_RIGHT_HIP, "right_hip" },
77  { Joint::TYPE_RIGHT_KNEE, "right_knee" },
78  { Joint::TYPE_RIGHT_FOOT, "right_foot" }
79  };
80 
81  // Used for some record-keeping during skeleton
82  // construction
83  struct Node
84  {
85  std::uint8_t type;
86  std::uint8_t parent_type;
87  };
88 }
89 
90 std::vector<geometry_msgs::TransformStamped> astra_ros::bodyTransforms(const Body &body)
91 {
92  const auto frame_id = [&](const std::uint8_t type) -> std::string {
93  const auto it = TF_FRAME_NAMES.find(type);
94  if (it == TF_FRAME_NAMES.cend())
95  {
96  std::ostringstream o;
97  o << "Unknown frame name for joint type " << static_cast<std::size_t>(type);
98  throw std::runtime_error(o.str());
99  }
100 
101  std::ostringstream o;
102  o << "humanoid/" << static_cast<std::size_t>(body.id) << "/" << it->second;
103  return o.str();
104  };
105 
106  std::unordered_map<std::uint8_t, const Joint *> lookup_map;
107 
108  // Helper function to look up a joint with caching (to avoid O(n^2)),
109  // though with hashmap allocation the performance might not be
110  // better for n = number of joints.
111  const auto lookup = [&](std::uint8_t type) -> const Joint * {
112  const auto it = lookup_map.find(type);
113  if (it != lookup_map.cend()) return it->second;
114 
115  for (const auto &joint : body.joints)
116  {
117  if (joint.type != type) continue;
118 
119  lookup_map[type] = &joint;
120  return &joint;
121  }
122 
123  return nullptr;
124  };
125 
126  tf2::BufferCore buffer;
127 
128  for (const auto &joint : body.joints)
129  {
130  geometry_msgs::TransformStamped transform;
131  transform.header = body.header;
132  transform.child_frame_id = frame_id(joint.type);
133 
134  auto &translation = transform.transform.translation;
135  translation.x = joint.pose.position.x;
136  translation.y = joint.pose.position.y;
137  translation.z = joint.pose.position.z;
138 
139  transform.transform.rotation = joint.pose.orientation;
140  buffer.setTransform(transform, std::string());
141  }
142 
143 
144  std::vector<geometry_msgs::TransformStamped> ret;
145 
146  Node root;
147  root.type = Joint::TYPE_BASE_SPINE;
148  root.parent_type = Joint::TYPE_UNKNOWN;
149 
150  std::deque<Node> queue { root };
151 
152  while (!queue.empty())
153  {
154  // Get current
155  const Node current = queue.front();
156  queue.pop_front();
157 
158  ret.push_back(buffer.lookupTransform(
159  current.parent_type != Joint::TYPE_UNKNOWN ? frame_id(current.parent_type) : body.header.frame_id,
160  frame_id(current.type),
161  ros::Time(0)
162  ));
163 
164  // Push current's children for processing
165  const auto links_it = TF_LINKS.find(current.type);
166  if (links_it == TF_LINKS.cend()) continue;
167 
168  for (auto it = links_it->second.cbegin(); it != links_it->second.cend(); ++it)
169  {
170  Node child;
171  child.type = *it;
172  child.parent_type = current.type;
173  queue.push_back(child);
174  }
175  }
176 
177  return ret;
178 }
179 
astra_ros::bodyTransforms
std::vector< geometry_msgs::TransformStamped > bodyTransforms(const Body &body)
Definition: tf.cpp:90
tf2::BufferCore::setTransform
bool setTransform(const geometry_msgs::TransformStamped &transform, const std::string &authority, bool is_static=false)
tf2::BufferCore::lookupTransform
geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const ros::Time &target_time, const std::string &source_frame, const ros::Time &source_time, const std::string &fixed_frame) const
tf.hpp
buffer_core.h
ros::Time
tf2::BufferCore
math.hpp
astra_ros
Definition: Device.hpp:14


astra_ros
Author(s): Braden McDorman
autogenerated on Wed Mar 2 2022 00:53:06