Skip to content
This repository was archived by the owner on Jul 23, 2024. It is now read-only.

Commit 8d74d9b

Browse files
vineet131aprotyas
andauthored
Fix for issue ros#431 - Covariance is not transformed in do_transform_pose_with_covariance_stamped (ros#453)
* -Fixed the issue of covariance not being transformed in do_transform_pose_with_covariance_stamped, corresponding to ros2/geometry2#431 and made the same changes as the C++ API Co-authored-by: Abrar Rahman Protyasha <[email protected]>
1 parent 8e508d0 commit 8d74d9b

File tree

2 files changed

+132
-2
lines changed

2 files changed

+132
-2
lines changed

tf2_geometry_msgs/scripts/test.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
import rclpy
3838
import tf2_geometry_msgs
3939
import tf2_ros
40-
40+
import numpy as np
4141

4242
class GeometryMsgs(unittest.TestCase):
4343

@@ -135,6 +135,46 @@ def test_transform(self):
135135
self.assertEqual(out.vector.y, 0)
136136
self.assertEqual(out.vector.z, 0)
137137

138+
# Testing for pose and covariance transform
139+
t = TransformStamped()
140+
t.transform.translation.x = 1.0
141+
t.transform.translation.y = 2.0
142+
t.transform.translation.z = 3.0
143+
t.transform.rotation = Quaternion(w=0.0, x=1.0, y=0.0, z=0.0)
144+
145+
v = PoseWithCovarianceStamped()
146+
v.header.stamp = rclpy.time.Time(seconds=2.0).to_msg()
147+
v.header.frame_id = 'a'
148+
v.pose.covariance = (
149+
1.0, 2.0, 3.0, 4.0, 5.0, 6.0,
150+
1.0, 2.0, 3.0, 4.0, 5.0, 6.0,
151+
1.0, 2.0, 3.0, 4.0, 5.0, 6.0,
152+
1.0, 2.0, 3.0, 4.0, 5.0, 6.0,
153+
1.0, 2.0, 3.0, 4.0, 5.0, 6.0,
154+
1.0, 2.0, 3.0, 4.0, 5.0, 6.0
155+
)
156+
v.pose.pose.position.x = 1.0
157+
v.pose.pose.position.y = 2.0
158+
v.pose.pose.position.z = 3.0
159+
v.pose.pose.orientation = Quaternion(w=0.0, x=1.0, y=0.0, z=0.0)
160+
161+
out = tf2_geometry_msgs.do_transform_pose_with_covariance_stamped(v, t)
162+
expected_covariance = np.array([
163+
1.0, -2.0, -3.0, 4.0, -5.0, -6.0,
164+
-1.0, 2.0, 3.0, -4.0, 5.0, 6.0,
165+
-1.0, 2.0, 3.0, -4.0, 5.0, 6.0,
166+
1.0, -2.0, -3.0, 4.0, -5.0, -6.0,
167+
-1.0, 2.0, 3.0, -4.0, 5.0, 6.0,
168+
-1.0, 2.0, 3.0, -4.0, 5.0, 6.0
169+
])
170+
self.assertEqual(out.pose.pose.position.x, 2)
171+
self.assertEqual(out.pose.pose.position.y, 0)
172+
self.assertEqual(out.pose.pose.position.z, 0)
173+
self.assertEqual(out.pose.orientation.x, 0)
174+
self.assertEqual(out.pose.orientation.y, 0)
175+
self.assertEqual(out.pose.orientation.z, 0)
176+
self.assertEqual(out.pose.orientation.w, 1)
177+
self.assertTrue(np.array_equal(out.pose.covariance, expected_covariance))
138178

139179
if __name__ == '__main__':
140180
rclpy.init(args=None)

tf2_geometry_msgs/src/tf2_geometry_msgs/tf2_geometry_msgs.py

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
from geometry_msgs.msg import (PointStamped, PoseStamped,
3333
PoseWithCovarianceStamped, Vector3Stamped)
34+
import numpy as np
3435
import PyKDL
3536
import tf2_ros
3637

@@ -62,6 +63,95 @@ def transform_to_kdl(t):
6263
t.transform.translation.y,
6364
t.transform.translation.z))
6465

66+
def transform_covariance(cov_in, transform):
67+
# Converting the Quaternion to a Rotation Matrix first
68+
# Taken from: https://automaticaddison.com/how-to-convert-a-quaternion-to-a-rotation-matrix/
69+
q0 = transform.transform.rotation.w
70+
q1 = transform.transform.rotation.x
71+
q2 = transform.transform.rotation.y
72+
q3 = transform.transform.rotation.z
73+
74+
# First row of the rotation matrix
75+
r00 = 2 * (q0 * q0 + q1 * q1) - 1
76+
r01 = 2 * (q1 * q2 - q0 * q3)
77+
r02 = 2 * (q1 * q3 + q0 * q2)
78+
79+
# Second row of the rotation matrix
80+
r10 = 2 * (q1 * q2 + q0 * q3)
81+
r11 = 2 * (q0 * q0 + q2 * q2) - 1
82+
r12 = 2 * (q2 * q3 - q0 * q1)
83+
84+
# Third row of the rotation matrix
85+
r20 = 2 * (q1 * q3 - q0 * q2)
86+
r21 = 2 * (q2 * q3 + q0 * q1)
87+
r22 = 2 * (q0 * q0 + q3 * q3) - 1
88+
89+
# Code reference: https://github.com/ros2/geometry2/pull/430
90+
# Mathematical Reference:
91+
# A. L. Garcia, “Linear Transformations of Random Vectors,” in Probability,
92+
# Statistics, and Random Processes For Electrical Engineering, 3rd ed.,
93+
# Pearson Prentice Hall, 2008, pp. 320–322.
94+
95+
R = np.array([[r00, r01, r02],
96+
[r10, r11, r12],
97+
[r20, r21, r22]])
98+
99+
R_transpose = np.transpose(R)
100+
101+
cov_11 = np.array([cov_in[:3], cov_in[6:9], cov_in[12:15]])
102+
cov_12 = np.array([cov_in[3:6], cov_in[9:12], cov_in[15:18]])
103+
cov_21 = np.array([cov_in[18:21], cov_in[24:27], cov_in[30:33]])
104+
cov_22 = np.array([cov_in[21:24], cov_in[27:30], cov_in[33:]])
105+
106+
# And we perform the transform
107+
result_11 = R @ cov_11 @ R_transpose
108+
result_12 = R @ cov_12 @ R_transpose
109+
result_21 = R @ cov_21 @ R_transpose
110+
result_22 = R @ cov_22 @ R_transpose
111+
112+
cov_out = PoseWithCovarianceStamped()
113+
114+
cov_out.pose.covariance[0] = result_11[0][0]
115+
cov_out.pose.covariance[1] = result_11[0][1]
116+
cov_out.pose.covariance[2] = result_11[0][2]
117+
cov_out.pose.covariance[6] = result_11[1][0]
118+
cov_out.pose.covariance[7] = result_11[1][1]
119+
cov_out.pose.covariance[8] = result_11[1][2]
120+
cov_out.pose.covariance[12] = result_11[2][0]
121+
cov_out.pose.covariance[13] = result_11[2][1]
122+
cov_out.pose.covariance[14] = result_11[2][2]
123+
124+
cov_out.pose.covariance[3] = result_12[0][0]
125+
cov_out.pose.covariance[4] = result_12[0][1]
126+
cov_out.pose.covariance[5] = result_12[0][2]
127+
cov_out.pose.covariance[9] = result_12[1][0]
128+
cov_out.pose.covariance[10] = result_12[1][1]
129+
cov_out.pose.covariance[11] = result_12[1][2]
130+
cov_out.pose.covariance[15] = result_12[2][0]
131+
cov_out.pose.covariance[16] = result_12[2][1]
132+
cov_out.pose.covariance[17] = result_12[2][2]
133+
134+
cov_out.pose.covariance[18] = result_21[0][0]
135+
cov_out.pose.covariance[19] = result_21[0][1]
136+
cov_out.pose.covariance[20] = result_21[0][2]
137+
cov_out.pose.covariance[24] = result_21[1][0]
138+
cov_out.pose.covariance[25] = result_21[1][1]
139+
cov_out.pose.covariance[26] = result_21[1][2]
140+
cov_out.pose.covariance[30] = result_21[2][0]
141+
cov_out.pose.covariance[31] = result_21[2][1]
142+
cov_out.pose.covariance[32] = result_21[2][2]
143+
144+
cov_out.pose.covariance[21] = result_22[0][0]
145+
cov_out.pose.covariance[22] = result_22[0][1]
146+
cov_out.pose.covariance[23] = result_22[0][2]
147+
cov_out.pose.covariance[27] = result_22[1][0]
148+
cov_out.pose.covariance[28] = result_22[1][1]
149+
cov_out.pose.covariance[29] = result_22[1][2]
150+
cov_out.pose.covariance[33] = result_22[2][0]
151+
cov_out.pose.covariance[34] = result_22[2][1]
152+
cov_out.pose.covariance[35] = result_22[2][2]
153+
154+
return cov_out.pose.covariance
65155

66156
# PointStamped
67157
def do_transform_point(point, transform):
@@ -140,7 +230,7 @@ def do_transform_pose_with_covariance_stamped(pose, transform):
140230
res.pose.pose.orientation.y,
141231
res.pose.pose.orientation.z,
142232
res.pose.pose.orientation.w) = f.M.GetQuaternion()
143-
res.pose.covariance = pose.pose.covariance
233+
res.pose.covariance = transform_covariance(pose.pose.covariance, transform)
144234
res.header = transform.header
145235
return res
146236

0 commit comments

Comments
 (0)