Skip to content

Commit a2fb16c

Browse files
committed
Run corrected_odom script to provide odometry velocity relative to the robot frame
1 parent d4dab76 commit a2fb16c

3 files changed

Lines changed: 120 additions & 0 deletions

File tree

spot_driver/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,12 @@ install(
245245
DESTINATION lib/${PROJECT_NAME}
246246
RENAME spot_ros2
247247
)
248+
install(
249+
PROGRAMS
250+
spot_driver/corrected_odom.py
251+
DESTINATION lib/${PROJECT_NAME}
252+
RENAME corrected_odom
253+
)
248254
install(
249255
PROGRAMS
250256
spot_driver/calibrated_reregistered_hand_camera_depth_publisher.py

spot_driver/launch/spot_driver.launch.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ def launch_setup(context: LaunchContext, ld: LaunchDescription) -> None:
8080
)
8181
ld.add_action(spot_driver_node)
8282

83+
corrected_odom_node = Node(
84+
package="spot_driver",
85+
executable="corrected_odom",
86+
name="corrected_odom",
87+
output="screen",
88+
parameters=[configured_params, spot_driver_params],
89+
namespace=spot_name,
90+
)
91+
ld.add_action(corrected_odom_node)
92+
8393
spot_lease_manager_node = Node(
8494
package="spot_driver",
8595
executable="lease_manager_node",
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#!/usr/bin/env python3
2+
3+
import rclpy
4+
import copy
5+
import transforms3d
6+
import numpy as np
7+
8+
from rclpy.node import Node
9+
from nav_msgs.msg import Odometry
10+
11+
"""
12+
The Spot ROS 2 driver reports the Twist part of the odometry in odom frame.
13+
According to ROS standards this should be reported in body frame.
14+
This script subscribes to the odometry, transforms it to body frame and publishes it
15+
to /odometry_corrected.
16+
"""
17+
18+
19+
class OdometryTransformer(Node):
20+
21+
def __init__(self):
22+
super().__init__('odometry_transformer')
23+
24+
self.odom_pub = self.create_publisher(
25+
Odometry,
26+
'/odometry_corrected',
27+
10)
28+
29+
self.odom_sub = self.create_subscription(
30+
Odometry,
31+
'/odometry',
32+
self.odometry_callback,
33+
10)
34+
self.odom_sub # prevent unused variable warning
35+
36+
def odometry_callback(self, msg):
37+
transformed_odom = self.transform_odom(msg)
38+
39+
self.odom_pub.publish(transformed_odom)
40+
41+
def transform_odom(self, base_odometry: Odometry):
42+
"""
43+
Copied from the ROS 1 fix:
44+
https://github.com/heuristicus/spot_ros/blob/2a1d26da976a6376b21b5af9ce5328899fb7a8c4/spot_driver/src/spot_driver/ros_helpers.py#L402
45+
"""
46+
47+
# Current inverse rotation of body frame w.r.t. odom frame
48+
inverse_rotation = transforms3d.quaternions.quat2mat(
49+
transforms3d.quaternions.qinverse(
50+
[
51+
base_odometry.pose.pose.orientation.w,
52+
base_odometry.pose.pose.orientation.x,
53+
base_odometry.pose.pose.orientation.y,
54+
base_odometry.pose.pose.orientation.z,
55+
]
56+
)
57+
)
58+
59+
# Transform the linear twist by rotating the vector according to the rotation from body to odom
60+
linear_twist = np.array(
61+
[
62+
[base_odometry.twist.twist.linear.x],
63+
[base_odometry.twist.twist.linear.y],
64+
[base_odometry.twist.twist.linear.z],
65+
]
66+
)
67+
68+
corrected_linear = inverse_rotation.dot(linear_twist)
69+
70+
# Do the same for the angular twist
71+
angular_twist = np.array(
72+
[
73+
[base_odometry.twist.twist.angular.x],
74+
[base_odometry.twist.twist.angular.y],
75+
[base_odometry.twist.twist.angular.z],
76+
]
77+
)
78+
79+
corrected_angular = inverse_rotation.dot(angular_twist)
80+
81+
corrected_odometry = copy.deepcopy(base_odometry)
82+
corrected_odometry.twist.twist.linear.x = corrected_linear[0][0]
83+
corrected_odometry.twist.twist.linear.y = corrected_linear[1][0]
84+
corrected_odometry.twist.twist.linear.z = corrected_linear[2][0]
85+
corrected_odometry.twist.twist.angular.x = corrected_angular[0][0]
86+
corrected_odometry.twist.twist.angular.y = corrected_angular[1][0]
87+
corrected_odometry.twist.twist.angular.z = corrected_angular[2][0]
88+
89+
return corrected_odometry
90+
91+
92+
def main(args=None):
93+
rclpy.init(args=args)
94+
95+
odometry_transformer = OdometryTransformer()
96+
97+
rclpy.spin(odometry_transformer)
98+
99+
odometry_transformer.destroy_node()
100+
rclpy.shutdown()
101+
102+
103+
if __name__ == '__main__':
104+
main()

0 commit comments

Comments
 (0)