Skip to content

Commit 824bb21

Browse files
committed
Add Eigen buffer transform tests
1 parent 5701c29 commit 824bb21

File tree

1 file changed

+181
-1
lines changed

1 file changed

+181
-1
lines changed

tf2_eigen/test/tf2_eigen-test.cpp

Lines changed: 181 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,16 @@
3434

3535
// To get M_PI, especially on Windows.
3636
#include <math.h>
37+
#include <memory>
3738

3839
#include <tf2_eigen/tf2_eigen.h>
3940
#include <gtest/gtest.h>
41+
#include <rclcpp/clock.hpp>
42+
#include <tf2_ros/transform_listener.h>
43+
#include <tf2_ros/buffer.h>
4044
#include <tf2/convert.h>
45+
#include <geometry_msgs/msg/vector3_stamped.hpp>
46+
#include <geometry_msgs/msg/quaternion_stamped.hpp>
4147

4248
TEST(TfEigen, ConvertVector3dStamped)
4349
{
@@ -133,7 +139,181 @@ TEST(TfEigen, ConvertTransform)
133139
EXPECT_TRUE(tm.isApprox(Iback.matrix()));
134140
}
135141

136-
int main(int argc, char **argv){
142+
struct EigenBufferTransform : public ::testing::Test
143+
{
144+
static void SetUpTestSuite()
145+
{
146+
rclcpp::Clock::SharedPtr clock = std::make_shared<rclcpp::Clock>(RCL_SYSTEM_TIME);
147+
tf_buffer = std::make_unique<tf2_ros::Buffer>(clock);
148+
tf_buffer->setUsingDedicatedThread(true);
149+
150+
// populate buffer
151+
geometry_msgs::msg::TransformStamped t;
152+
t.transform.translation.x = 10;
153+
t.transform.translation.y = 20;
154+
t.transform.translation.z = 30;
155+
t.transform.rotation.w = 0;
156+
t.transform.rotation.x = 1;
157+
t.transform.rotation.y = 0;
158+
t.transform.rotation.z = 0;
159+
t.header.stamp = tf2_ros::toMsg(tf2::timeFromSec(2));
160+
t.header.frame_id = "A";
161+
t.child_frame_id = "B";
162+
tf_buffer->setTransform(t, "test");
163+
}
164+
165+
166+
template<int mode>
167+
void testEigenTransform();
168+
169+
::testing::AssertionResult doTestEigenQuaternion(
170+
const Eigen::Quaterniond & parameter,
171+
const Eigen::Quaterniond & expected);
172+
173+
static std::unique_ptr<tf2_ros::Buffer> tf_buffer;
174+
static constexpr double EPS = 1e-3;
175+
};
176+
177+
std::unique_ptr<tf2_ros::Buffer> EigenBufferTransform::tf_buffer;
178+
179+
template<int mode>
180+
void EigenBufferTransform::testEigenTransform()
181+
{
182+
using T = Eigen::Transform<double, 3, mode>;
183+
using stampedT = tf2::Stamped<T>;
184+
185+
geometry_msgs::msg::PoseStamped v1;
186+
v1.pose.position.x = 1;
187+
v1.pose.position.y = 2;
188+
v1.pose.position.z = 3;
189+
v1.pose.orientation.w = 0;
190+
v1.pose.orientation.x = 1;
191+
v1.pose.orientation.y = 0;
192+
v1.pose.orientation.z = 0;
193+
v1.header.stamp = tf2_ros::toMsg(tf2::timeFromSec(2));
194+
v1.header.frame_id = "A";
195+
196+
stampedT i1;
197+
tf2::convert(v1, i1);
198+
199+
// simple api
200+
const stampedT i_simple = tf_buffer->transform(i1, "B", tf2::durationFromSec(2.0));
201+
EXPECT_NEAR(i_simple.translation().x(), -9, EPS);
202+
EXPECT_NEAR(i_simple.translation().y(), 18, EPS);
203+
EXPECT_NEAR(i_simple.translation().z(), 27, EPS);
204+
const auto q1 = Eigen::Quaterniond(i_simple.linear());
205+
EXPECT_NEAR(q1.x(), 0.0, EPS);
206+
EXPECT_NEAR(q1.y(), 0.0, EPS);
207+
EXPECT_NEAR(q1.z(), 0.0, EPS);
208+
EXPECT_NEAR(q1.w(), 1.0, EPS);
209+
210+
geometry_msgs::msg::PoseStamped v_simple;
211+
tf2::convert(i_simple, v_simple);
212+
EXPECT_NEAR(v_simple.pose.position.x, -9, EPS);
213+
EXPECT_NEAR(v_simple.pose.position.y, 18, EPS);
214+
EXPECT_NEAR(v_simple.pose.position.z, 27, EPS);
215+
EXPECT_NEAR(v_simple.pose.orientation.x, 0.0, EPS);
216+
EXPECT_NEAR(v_simple.pose.orientation.y, 0.0, EPS);
217+
EXPECT_NEAR(v_simple.pose.orientation.z, 0.0, EPS);
218+
EXPECT_NEAR(v_simple.pose.orientation.w, 1.0, EPS);
219+
220+
221+
// advanced api
222+
const stampedT v_advanced = tf_buffer->transform(
223+
i1, "B", tf2::timeFromSec(2.0),
224+
"A", tf2::durationFromSec(3.0));
225+
EXPECT_NEAR(v_advanced.translation().x(), -9, EPS);
226+
EXPECT_NEAR(v_advanced.translation().y(), 18, EPS);
227+
EXPECT_NEAR(v_advanced.translation().z(), 27, EPS);
228+
const auto q2 = Eigen::Quaterniond(v_advanced.linear());
229+
EXPECT_NEAR(q2.x(), 0.0, EPS);
230+
EXPECT_NEAR(q2.y(), 0.0, EPS);
231+
EXPECT_NEAR(q2.z(), 0.0, EPS);
232+
EXPECT_NEAR(q2.w(), 1.0, EPS);
233+
}
234+
235+
TEST_F(EigenBufferTransform, Affine3d)
236+
{
237+
testEigenTransform<Eigen::Affine>();
238+
}
239+
240+
TEST_F(EigenBufferTransform, Isometry3d)
241+
{
242+
testEigenTransform<Eigen::Isometry>();
243+
}
244+
245+
TEST_F(EigenBufferTransform, Vector)
246+
{
247+
const tf2::Stamped<Eigen::Vector3d> v1 {{1, 2, 3}, tf2::timeFromSec(2), "A"};
248+
249+
// simple api
250+
const tf2::Stamped<Eigen::Vector3d> v_simple =
251+
tf_buffer->transform(v1, "B", tf2::durationFromSec(2.0));
252+
EXPECT_NEAR(v_simple.x(), -9, EPS);
253+
EXPECT_NEAR(v_simple.y(), 18, EPS);
254+
EXPECT_NEAR(v_simple.z(), 27, EPS);
255+
256+
// advanced api
257+
const tf2::Stamped<Eigen::Vector3d> v_advanced = tf_buffer->transform(
258+
v1, "B", tf2::timeFromSec(2.0),
259+
"A", tf2::durationFromSec(3.0));
260+
EXPECT_NEAR(v_advanced.x(), -9, EPS);
261+
EXPECT_NEAR(v_advanced.y(), 18, EPS);
262+
EXPECT_NEAR(v_advanced.z(), 27, EPS);
263+
}
264+
265+
// helper method for Quaternion tests
266+
::testing::AssertionResult EigenBufferTransform::doTestEigenQuaternion(
267+
const Eigen::Quaterniond & parameter, const Eigen::Quaterniond & expected)
268+
{
269+
const tf2::Stamped<Eigen::Quaterniond> q1 {parameter, tf2::timeFromSec(2), "A"};
270+
// avoid linking error
271+
const double eps = EPS;
272+
273+
// simple api
274+
const tf2::Stamped<Eigen::Quaterniond> q_simple =
275+
tf_buffer->transform(q1, "B", tf2::durationFromSec(2.0));
276+
// compare rotation matrices, as the quaternions can be ambigous
277+
EXPECT_TRUE(q_simple.toRotationMatrix().isApprox(expected.toRotationMatrix(), eps));
278+
279+
// advanced api
280+
const tf2::Stamped<Eigen::Quaterniond> q_advanced = tf_buffer->transform(
281+
q1, "B", tf2::timeFromSec(2.0),
282+
"A", tf2::durationFromSec(3.0));
283+
EXPECT_TRUE(q_advanced.toRotationMatrix().isApprox(expected.toRotationMatrix(), eps));
284+
return ::testing::AssertionSuccess();
285+
}
286+
287+
TEST_F(EigenBufferTransform, QuaternionRotY)
288+
{
289+
// rotated by -90° around y
290+
// 0, 0, -1
291+
// 0, 1, 0,
292+
// 1, 0, 0
293+
const Eigen::Quaterniond param{Eigen::AngleAxisd(-1 * M_PI_2, Eigen::Vector3d::UnitY())};
294+
const Eigen::Quaterniond expected{0, M_SQRT1_2, 0, -1 * M_SQRT1_2};
295+
EXPECT_TRUE(doTestEigenQuaternion(param, expected));
296+
}
297+
298+
TEST_F(EigenBufferTransform, QuaternionRotX)
299+
{
300+
// rotated by 90° around y
301+
const Eigen::Quaterniond param{Eigen::AngleAxisd(M_PI_2, Eigen::Vector3d::UnitX())};
302+
const Eigen::Quaterniond expected{Eigen::AngleAxisd(-1 * M_PI_2, Eigen::Vector3d::UnitX())};
303+
EXPECT_TRUE(doTestEigenQuaternion(param, expected));
304+
}
305+
306+
TEST_F(EigenBufferTransform, QuaternionRotZ)
307+
{
308+
// rotated by 180° around z
309+
const Eigen::Quaterniond param{Eigen::AngleAxisd(M_PI, Eigen::Vector3d::UnitZ())};
310+
const Eigen::Quaterniond expected{Eigen::AngleAxisd(M_PI, Eigen::Vector3d::UnitY())};
311+
EXPECT_TRUE(doTestEigenQuaternion(param, expected));
312+
}
313+
314+
315+
int main(int argc, char ** argv)
316+
{
137317
testing::InitGoogleTest(&argc, argv);
138318

139319
return RUN_ALL_TESTS();

0 commit comments

Comments
 (0)